From fcc5eb9f87a476115cc742bf45056ccbbc830057 Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Sun, 16 Jan 2022 21:41:44 +0100 Subject: m + add b2sum MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- .gitignore | 1 + Makefile | 30 +++++-- b224sum.1 | 6 ++ b256sum.1 | 6 ++ b2sum.1 | 88 ++++++++++++++++++ b2sum.c | 295 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ b384sum.1 | 6 ++ b512sum.1 | 6 ++ bsum.1 | 8 +- bsum.c | 269 ++++++++----------------------------------------------- common.c | 228 +++++++++++++++++++++++++++++++++++++++++++++++ common.h | 10 +++ 12 files changed, 710 insertions(+), 243 deletions(-) create mode 100644 b2sum.1 create mode 100644 b2sum.c create mode 100644 common.c diff --git a/.gitignore b/.gitignore index d17d682..f43afce 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ *.gcno *.gcda /bsum +/b2sum diff --git a/Makefile b/Makefile index 3f743a8..e09140b 100644 --- a/Makefile +++ b/Makefile @@ -3,31 +3,43 @@ CONFIGFILE = config.mk include $(CONFIGFILE) +BIN =\ + bsum\ + b2sum + OBJ =\ - bsum.o + $(BIN:=.o)\ + common.o HDR =\ arg.h\ common.h -all: bsum +all: $(BIN) $(OBJ): $(HDR) .c.o: $(CC) -c -o $@ $< $(CFLAGS) $(CPPFLAGS) -bsum: $(OBJ) - $(CC) -o $@ $(OBJ) $(LDFLAGS) +bsum: bsum.o common.o + $(CC) -o $@ $@.o common.o $(LDFLAGS) + +b2sum: b2sum.o common.o + $(CC) -o $@ $@.o common.o $(LDFLAGS) -install: bsum +install: $(BIN) mkdir -p -- "$(DESTDIR)$(PREFIX)/bin" mkdir -p -- "$(DESTDIR)$(MANPREFIX)/man1/" - cp -- bsum "$(DESTDIR)$(PREFIX)/bin/" + cp -- $(BIN) "$(DESTDIR)$(PREFIX)/bin/" ln -sf -- bsum "$(DESTDIR)$(PREFIX)/bin/b224sum" ln -sf -- bsum "$(DESTDIR)$(PREFIX)/bin/b256sum" ln -sf -- bsum "$(DESTDIR)$(PREFIX)/bin/b384sum" ln -sf -- bsum "$(DESTDIR)$(PREFIX)/bin/b512sum" - cp -- bsum.1 "$(DESTDIR)$(MANPREFIX)/man1/" + cp -- $(BIN:=.1) "$(DESTDIR)$(MANPREFIX)/man1/" + cp -- b224sum.1 "$(DESTDIR)$(MANPREFIX)/man1/b224sum.1" + cp -- b256sum.1 "$(DESTDIR)$(MANPREFIX)/man1/b256sum.1" + cp -- b384sum.1 "$(DESTDIR)$(MANPREFIX)/man1/b384sum.1" + cp -- b512sum.1 "$(DESTDIR)$(MANPREFIX)/man1/b512sum.1" uninstall: -rm -f -- "$(DESTDIR)$(PREFIX)/bin/bsum" @@ -35,15 +47,17 @@ uninstall: -rm -f -- "$(DESTDIR)$(PREFIX)/bin/b256sum" -rm -f -- "$(DESTDIR)$(PREFIX)/bin/b384sum" -rm -f -- "$(DESTDIR)$(PREFIX)/bin/b512sum" + -rm -f -- "$(DESTDIR)$(PREFIX)/bin/b2sum" -rm -f -- "$(DESTDIR)$(MANPREFIX)/man1/bsum.1" -rm -f -- "$(DESTDIR)$(MANPREFIX)/man1/b224sum.1" -rm -f -- "$(DESTDIR)$(MANPREFIX)/man1/b256sum.1" -rm -f -- "$(DESTDIR)$(MANPREFIX)/man1/b384sum.1" -rm -f -- "$(DESTDIR)$(MANPREFIX)/man1/b512sum.1" + -rm -f -- "$(DESTDIR)$(MANPREFIX)/man1/b2sum.1" clean: -rm -f -- *.o *.su *.gcov *.gcno *.gcda - -rm -f -- bsum + -rm -f -- $(BIN) .SUFFIXES: .SUFFIXES: .o .c diff --git a/b224sum.1 b/b224sum.1 index 82c6a48..874535a 100644 --- a/b224sum.1 +++ b/b224sum.1 @@ -66,3 +66,9 @@ Checksums did not match or a file did not exist. .TP 2 An error occurred. +.SH SEE ALSO +.BR bsum (1), +.BR b2sum (1), +.BR b256sum (1), +.BR b384sum (1), +.BR b512sum (1) diff --git a/b256sum.1 b/b256sum.1 index 4998b57..039ee51 100644 --- a/b256sum.1 +++ b/b256sum.1 @@ -66,3 +66,9 @@ Checksums did not match or a file did not exist. .TP 2 An error occurred. +.SH SEE ALSO +.BR bsum (1), +.BR b2sum (1), +.BR b224sum (1), +.BR b384sum (1), +.BR b512sum (1) diff --git a/b2sum.1 b/b2sum.1 new file mode 100644 index 0000000..a4e1f4b --- /dev/null +++ b/b2sum.1 @@ -0,0 +1,88 @@ +.TH B2SUM 1 blakesum +.SH NAME +b2sum - Compute and check BLAKE2 message digests +.SH SYNOPSIS +.B bsum +[-l bits | -X bits] [-c | -B | -L | -U] [-sxz] +.RI [ file "] ..." +.SH DESCRIPTION +Print or check BLAKE2 checksums, using BLAKE2b by default. +.SH OPTIONS +The +.B b2sum +utility conforms to the Base Definitions volume of POSIX.1-2017, +.IR "Section 12.2" , +.IR "Utility Syntax Guidelines" . +.PP +The following options are supported: +.TP +.B -B +Output checksums in binary representation. This suppresses +the filenames and checksum delimiters. Only the checksums +are printed. +.TP +.B -c +Read BLAKE2 sums from the file and check them against the +files on your systems. The input files files should be +formatted as the output of this program, or similarly. +This is not going to work if any of the filenames in the +input files starts with or , or if they +contain a size) + buf = erealloc(buf, size); + if (flag_small) + libblake_blake2s_digest(&state2s, buf, len, 0, hashlen / 8, hash); + else + libblake_blake2b_digest(&state2b, buf, len, 0, hashlen / 8, hash); + free(buf); + return 0; +} + +static int +hash_fd_blake2bsx(int fd, const char *fname, int decode_hex, unsigned char hash[]) +{ + struct libblake_blake2xb_state state2xb; + struct libblake_blake2xb_params params2xb; + struct libblake_blake2xs_state state2xs; + struct libblake_blake2xs_params params2xs; + char *buf = NULL; + size_t size = 0; + size_t len = 0; + size_t off = 0; + size_t req; + size_t i, n; + ssize_t r; + int ok; + if (flag_small) { + memset(¶ms2xs, 0, sizeof(params2xs)); + params2xs.digest_len = (uint_least8_t)length; + params2xs.fanout = 1; + params2xs.depth = 1; + params2xs.xof_len = (uint_least16_t)xlength; + libblake_blake2xs_init(&state2xs, ¶ms2xs, NULL); + } else { + memset(¶ms2xb, 0, sizeof(params2xb)); + params2xb.digest_len = (uint_least8_t)length; + params2xb.fanout = 1; + params2xb.depth = 1; + params2xb.xof_len = (uint_least32_t)xlength; + libblake_blake2xb_init(&state2xb, ¶ms2xb, NULL); + } + for (;;) { + if (len == size) + buf = erealloc(buf, size += 8 << 10); + r = read(fd, &buf[len], size - len); + if (r <= 0) { + if (!r) + break; + if (errno == EINTR) + continue; + fprintf(stderr, "%s: %s: %s\n", argv0, fname, strerror(errno)); + free(buf); + return -1; + } + len += (size_t)r; + if (!decode_hex) { + if (flag_small) + off += libblake_blake2xs_update(&state2xs, &buf[off], len - off); + else + off += libblake_blake2xb_update(&state2xb, &buf[off], len - off); + if (off == len) + off = 0; + } + } + if (off) + memmove(&buf[0], &buf[off], len -= off); + if (decode_hex) { + len = libblake_decode_hex(buf, len, buf, &ok); + if (!ok) { + fprintf(stderr, "%s: %s: %s\n", argv0, fname, "invalid hexadecimal input"); + free(buf); + return -1; + } + } + if (flag_small) + req = libblake_blake2xs_predigest_get_required_input_size(&state2xs); + else + req = libblake_blake2xb_predigest_get_required_input_size(&state2xb); + if (req > size) + buf = erealloc(buf, size); + if (flag_small) + libblake_blake2xs_predigest(&state2xs, buf, len, 0); + else + libblake_blake2xb_predigest(&state2xb, buf, len, 0); + if (flag_small) { + for (i = 0; i * 32 < hashlen / 8; i++) { /* TODO this could be done parallel (also below) */ + n = (i + 1) * 32 > hashlen / 8 ? hashlen / 8 - i * 32 : 32; + libblake_blake2xs_digest(&state2xs, (uint_least32_t)i, (uint_least8_t)n, &hash[i * 32]); + } + } else { + for (i = 0; i * 64 < hashlen / 8; i++) { + n = (i + 1) * 64 > hashlen / 8 ? hashlen / 8 - i * 64 : 64; + libblake_blake2xb_digest(&state2xb, (uint_least32_t)i, (uint_least8_t)n, &hash[i * 64]); + } + } + free(buf); + return 0; +} + +int +hash_fd(int fd, const char *fname, int decode_hex, unsigned char hash[]) +{ + int ret; + + if (flag_extended) + ret = hash_fd_blake2bsx(fd, fname, decode_hex, hash); + else + ret = hash_fd_blake2bs(fd, fname, decode_hex, hash); + + return ret; +} + +int +main(int argc, char *argv[]) +{ + int status = 0; + int output_case; + char newline; + + ARGBEGIN { + case 'c': + flag_check = 1; + break; + case 'B': + flag_binary = 1; + break; + case 'L': + flag_lower = 1; + flag_upper = 0; + break; + case 'U': + flag_upper = 1; + flag_lower = 0; + break; + case 's': + flag_small = 1; + break; + case 'x': + flag_hex = 1; + break; + case 'z': + flag_zero = 1; + break; + case 'l': + if (length) + usage(); + length = atoi(ARG()); + if (length & 7 || !length || length > 512) { + fprintf(stderr, "%s: valid arguments for -l\n", argv0); + return 2; + } + break; + case 'X': + if (flag_extended) + usage(); + flag_extended = 1; + xlength = atoll(ARG()); + if (xlength & 7 || !xlength || xlength > 34359738360LL) { + fprintf(stderr, "%s: valid arguments for -X\n", argv0); + return 2; + } + break; + default: + usage(); + } ARGEND; + + if (flag_check + flag_binary + flag_lower + flag_upper > 1 || + (length && flag_extended)) + usage(); + + if (!length) + length = flag_small ? 256 : 512; + else if (flag_small && length > 256) + fprintf(stderr, "%s: valid arguments for -l\n", argv0); + else if (flag_small && xlength > 524280LL) + fprintf(stderr, "%s: valid arguments for -X\n", argv0); + + hashlen = flag_extended ? (size_t)xlength : (size_t)length; + length /= 8; + xlength /= 8; + + newline = flag_zero ? '\0' : '\n'; + if (flag_check) { + if (!argc) { + status |= -check_and_print("-", hashlen, flag_hex, newline); + } else { + for (; *argv; argv++) + status |= -check_and_print(*argv, hashlen, flag_hex, newline); + } + } else { + output_case = flag_binary ? -1 : flag_upper; + if (!argc) { + status |= -hash_and_print("-", hashlen, flag_hex, newline, output_case); + } else { + for (; *argv; argv++) + status |= -hash_and_print(*argv, hashlen, flag_hex, newline, output_case); + } + } + + if (fflush(stdout) || ferror(stdout) || fclose(stdout)) { + fprintf(stderr, "%s: %s\n", argv0, strerror(errno)); + return 2; + } + return status; +} diff --git a/b384sum.1 b/b384sum.1 index 925b698..d7f2eaf 100644 --- a/b384sum.1 +++ b/b384sum.1 @@ -66,3 +66,9 @@ Checksums did not match or a file did not exist. .TP 2 An error occurred. +.SH SEE ALSO +.BR bsum (1), +.BR b2sum (1), +.BR b224sum (1), +.BR b256sum (1), +.BR b512sum (1) diff --git a/b512sum.1 b/b512sum.1 index ebaf844..2c0fd00 100644 --- a/b512sum.1 +++ b/b512sum.1 @@ -66,3 +66,9 @@ Checksums did not match or a file did not exist. .TP 2 An error occurred. +.SH SEE ALSO +.BR bsum (1), +.BR b2sum (1), +.BR b224sum (1), +.BR b256sum (1), +.BR b384sum (1) diff --git a/bsum.1 b/bsum.1 index d8ca915..442af70 100644 --- a/bsum.1 +++ b/bsum.1 @@ -34,7 +34,7 @@ option is also used. .B -L Output checksums in lower-case hexadecimal representation. (Default) .TP -.B -l +.BI "-l " bits Select version of the BLAKE algorithm. Valid values are 224 (default), 256, 384, and 512. .TP @@ -70,3 +70,9 @@ Checksums did not match or a file did not exist. .TP 2 An error occurred. +.SH SEE ALSO +.BR b2sum (1), +.BR b224sum (1), +.BR b256sum (1), +.BR b384sum (1), +.BR b512sum (1) diff --git a/bsum.c b/bsum.c index cbc8b51..1940cf2 100644 --- a/bsum.c +++ b/bsum.c @@ -5,6 +5,14 @@ const char *argv0 = "bsum"; static int lenght_by_command_name = 0; +static int flag_check = 0; +static int flag_binary = 0; +static int flag_lower = 0; +static int flag_upper = 0; +static int flag_hex = 0; +static int flag_zero = 0; +static int length; + static void usage(void) { @@ -13,36 +21,24 @@ usage(void) exit(2); } -static void * -erealloc(void *ptr, size_t n) -{ - ptr = realloc(ptr, n); - if (!ptr) { - fprintf(stderr, "%s: %s\n", argv0, strerror(errno)); - exit(2); - } - return ptr; -} - static void get_lenght_by_command_name(const char *command) { const char *p; p = strrchr(command, '/'); p = p ? &p[1] : command; - if (strstr(p, "b224sum")) { + if (strstr(p, "b224sum")) lenght_by_command_name = 224; - } else if (strstr(p, "b256sum")) { + else if (strstr(p, "b256sum")) lenght_by_command_name = 256; - } else if (strstr(p, "b384sum")) { + else if (strstr(p, "b384sum")) lenght_by_command_name = 384; - } else if (strstr(p, "b512sum")) { + else if (strstr(p, "b512sum")) lenght_by_command_name = 512; - } } static int -hash_file_blake224(int fd, const char *fname, int decode_hex, unsigned char hash[], size_t *hash_lenp) +hash_fd_blake224(int fd, const char *fname, int decode_hex, unsigned char hash[]) { struct libblake_blake224_state state; char *buf = NULL; @@ -63,6 +59,7 @@ hash_file_blake224(int fd, const char *fname, int decode_hex, unsigned char hash if (errno == EINTR) continue; fprintf(stderr, "%s: %s: %s\n", argv0, fname, strerror(errno)); + free(buf); return -1; } len += (size_t)r; @@ -78,6 +75,7 @@ hash_file_blake224(int fd, const char *fname, int decode_hex, unsigned char hash len = libblake_decode_hex(buf, len, buf, &ok); if (!ok) { fprintf(stderr, "%s: %s: %s\n", argv0, fname, "invalid hexadecimal input"); + free(buf); return -1; } } @@ -85,13 +83,12 @@ hash_file_blake224(int fd, const char *fname, int decode_hex, unsigned char hash if (req > size) buf = erealloc(buf, size); libblake_blake224_digest(&state, buf, len, 0, NULL, hash); - *hash_lenp = LIBBLAKE_BLAKE224_OUTPUT_SIZE; free(buf); return 0; } static int -hash_file_blake256(int fd, const char *fname, int decode_hex, unsigned char hash[], size_t *hash_lenp) +hash_fd_blake256(int fd, const char *fname, int decode_hex, unsigned char hash[]) { struct libblake_blake256_state state; char *buf = NULL; @@ -112,6 +109,7 @@ hash_file_blake256(int fd, const char *fname, int decode_hex, unsigned char hash if (errno == EINTR) continue; fprintf(stderr, "%s: %s: %s\n", argv0, fname, strerror(errno)); + free(buf); return -1; } len += (size_t)r; @@ -127,6 +125,7 @@ hash_file_blake256(int fd, const char *fname, int decode_hex, unsigned char hash len = libblake_decode_hex(buf, len, buf, &ok); if (!ok) { fprintf(stderr, "%s: %s: %s\n", argv0, fname, "invalid hexadecimal input"); + free(buf); return -1; } } @@ -134,13 +133,12 @@ hash_file_blake256(int fd, const char *fname, int decode_hex, unsigned char hash if (req > size) buf = erealloc(buf, size); libblake_blake256_digest(&state, buf, len, 0, NULL, hash); - *hash_lenp = LIBBLAKE_BLAKE256_OUTPUT_SIZE; free(buf); return 0; } static int -hash_file_blake384(int fd, const char *fname, int decode_hex, unsigned char hash[], size_t *hash_lenp) +hash_fd_blake384(int fd, const char *fname, int decode_hex, unsigned char hash[]) { struct libblake_blake384_state state; char *buf = NULL; @@ -161,6 +159,7 @@ hash_file_blake384(int fd, const char *fname, int decode_hex, unsigned char hash if (errno == EINTR) continue; fprintf(stderr, "%s: %s: %s\n", argv0, fname, strerror(errno)); + free(buf); return -1; } len += (size_t)r; @@ -176,6 +175,7 @@ hash_file_blake384(int fd, const char *fname, int decode_hex, unsigned char hash len = libblake_decode_hex(buf, len, buf, &ok); if (!ok) { fprintf(stderr, "%s: %s: %s\n", argv0, fname, "invalid hexadecimal input"); + free(buf); return -1; } } @@ -183,13 +183,12 @@ hash_file_blake384(int fd, const char *fname, int decode_hex, unsigned char hash if (req > size) buf = erealloc(buf, size); libblake_blake384_digest(&state, buf, len, 0, NULL, hash); - *hash_lenp = LIBBLAKE_BLAKE384_OUTPUT_SIZE; free(buf); return 0; } static int -hash_file_blake512(int fd, const char *fname, int decode_hex, unsigned char hash[], size_t *hash_lenp) +hash_fd_blake512(int fd, const char *fname, int decode_hex, unsigned char hash[]) { struct libblake_blake512_state state; char *buf = NULL; @@ -210,6 +209,7 @@ hash_file_blake512(int fd, const char *fname, int decode_hex, unsigned char hash if (errno == EINTR) continue; fprintf(stderr, "%s: %s: %s\n", argv0, fname, strerror(errno)); + free(buf); return -1; } len += (size_t)r; @@ -225,6 +225,7 @@ hash_file_blake512(int fd, const char *fname, int decode_hex, unsigned char hash len = libblake_decode_hex(buf, len, buf, &ok); if (!ok) { fprintf(stderr, "%s: %s: %s\n", argv0, fname, "invalid hexadecimal input"); + free(buf); return -1; } } @@ -232,232 +233,32 @@ hash_file_blake512(int fd, const char *fname, int decode_hex, unsigned char hash if (req > size) buf = erealloc(buf, size); libblake_blake512_digest(&state, buf, len, 0, NULL, hash); - *hash_lenp = LIBBLAKE_BLAKE512_OUTPUT_SIZE; free(buf); return 0; } -static int -parse_fd(const char *name) -{ - long int num; - char *end; - if (!isdigit(*name)) - return -1; - errno = 0; - num = strtol(name, &end, 10); - if (num > INT_MAX || *end || errno) - return -1; - return (int)num; -} - -static int -open_file(const char *path, int *closep) -{ - int fd = -1; - - *closep = 0; - - if (!strcmp(path, "-")) - fd = STDIN_FILENO; - else if (!strcmp(path, "/dev/stdin")) - fd = STDIN_FILENO; - else if (!strcmp(path, "/dev/stdout")) - fd = STDOUT_FILENO; - else if (!strcmp(path, "/dev/stderr")) - fd = STDERR_FILENO; - else if (!strncmp(path, "/dev/fd/", sizeof("/dev/fd/") - 1)) - fd = parse_fd(&path[sizeof("/dev/fd/") - 1]); - else if (!strncmp(path, "/proc/self/fd/", sizeof("/proc/self/fd/") - 1)) - fd = parse_fd(&path[sizeof("/proc/self/fd/") - 1]); - - if (fd < 0) { - fd = open(path, O_RDONLY); - if (fd < 0) - return -1; - *closep = 1; - } - - return fd; -} - -static int -hash_file(const char *path, int length, int decode_hex, unsigned char hash[], size_t *hash_lenp) +int +hash_fd(int fd, const char *fname, int decode_hex, unsigned char hash[]) { - int ret, fd, close_fd; - - fd = open_file(path, &close_fd); - if (fd < 0) { - fprintf(stderr, "%s: %s: %s\n", argv0, path, strerror(errno)); - return -1; - } + int ret; if (length == 224) - ret = hash_file_blake224(fd, path, decode_hex, hash, hash_lenp); + ret = hash_fd_blake224(fd, fname, decode_hex, hash); else if (length == 256) - ret = hash_file_blake256(fd, path, decode_hex, hash, hash_lenp); + ret = hash_fd_blake256(fd, fname, decode_hex, hash); else if (length == 384) - ret = hash_file_blake384(fd, path, decode_hex, hash, hash_lenp); + ret = hash_fd_blake384(fd, fname, decode_hex, hash); else if (length == 512) - ret = hash_file_blake512(fd, path, decode_hex, hash, hash_lenp); + ret = hash_fd_blake512(fd, fname, decode_hex, hash); else abort(); - if (close_fd) - close(fd); return ret; } -static int -hash_and_print(const char *path, int length, int decode_hex, char newline, int output_case) -{ - unsigned char hash[LIBBLAKE_BLAKE512_OUTPUT_SIZE]; - char hex[LIBBLAKE_BLAKE512_OUTPUT_SIZE * 2 + 1]; - size_t hash_len; - - if (hash_file(path, length, decode_hex, hash, &hash_len)) - return -1; - - if (output_case < 0) { - fwrite(hash, 1, hash_len, stdout); - } else { - libblake_encode_hex(hash, hash_len, hex, output_case); - printf("%s %s%c", hex, path, newline); - } - - return 0; -} - -static int -check_and_print_file(const char *path, int length, int decode_hex, char *expected) -{ - unsigned char hash[LIBBLAKE_BLAKE512_OUTPUT_SIZE]; - int r, fd, close_fd; - - fd = open_file(path, &close_fd); - if (fd < 0) { - if (errno != ENOENT) - fprintf(stderr, "%s: %s: %s\n", argv0, path, strerror(errno)); - missing: - printf("%s: Missing\n", path); - return -1; - } - - if (length == 224) - r = hash_file_blake224(fd, path, decode_hex, hash, &(size_t){0}); - else if (length == 256) - r = hash_file_blake256(fd, path, decode_hex, hash, &(size_t){0}); - else if (length == 384) - r = hash_file_blake384(fd, path, decode_hex, hash, &(size_t){0}); - else if (length == 512) - r = hash_file_blake512(fd, path, decode_hex, hash, &(size_t){0}); - else - abort(); - - if (close_fd) - close(fd); - - if (r < 0) - goto missing; - - libblake_decode_hex(expected, (size_t)length / 4, expected, &(int){0}); - if (!memcmp(hash, expected, (size_t)length / 8)) { - printf("%s: OK\n", path); - return 0; - } else { - printf("%s: Fail\n", path); - return -1; - } -} - -static int -check_and_print(const char *path, int length, int decode_hex, char newline) -{ - int fd, close_fd, status = 0; - char *buf = NULL; - size_t size = 0; - size_t len = 0; - ssize_t r; - size_t i, j, k; - - fd = open_file(path, &close_fd); - if (fd < 0) { - fprintf(stderr, "%s: %s: %s\n", argv0, path, strerror(errno)); - exit(2); - } - - for (;;) { - if (len == size) - buf = erealloc(buf, size += 8 << 10); - r = read(fd, &buf[len], size - len); - if (r > 0) { - len += (size_t)r; - } else if (!r) { - break; - } else if (errno == EINTR) { - continue; - } else { - fprintf(stderr, "%s: %s: %s\n", argv0, path, strerror(errno)); - exit(2); - } - } - buf = erealloc(buf, len + 1); - buf[len] = '\0'; - - if (newline) { - for (i = 0; i < len; i = k + 1) { - while (isspace(buf[i])) - i++; - for (j = i; j - i < (size_t)length / 4; j++) - if (!isxdigit(buf[j])) - goto corrupt; - if (j == len || !isblank(buf[j])) - goto corrupt; - buf[j] = '\0'; - j++; - while (isblank(buf[j])) - j++; - if (!buf[j]) - goto corrupt; - for (k = j; buf[k] && buf[k] != newline;) - k++; - buf[k] = '\0'; - status |= check_and_print_file(&buf[j], length, decode_hex, &buf[i]); - } - } else { - for (i = 0; i < len; i = k + 1) { - for (j = i; j - i < (size_t)length / 4; j++) - if (!isxdigit(buf[j])) - goto corrupt; - if (buf[j + 0] != ' ' || buf[j + 1] != ' ') - goto corrupt; - buf[j] = '\0'; - j += 2; - k = j + strlen(&buf[j]); - status |= check_and_print_file(&buf[j], length, decode_hex, &buf[i]); - } - } - - if (close_fd) - close(fd); - return status; - -corrupt: - fprintf(stderr, "%s: %s: invalid file content\n", argv0, path); - exit(2); -} - int main(int argc, char *argv[]) { - int flag_check = 0; - int flag_binary = 0; - int flag_lower = 0; - int flag_upper = 0; - int flag_hex = 0; - int flag_zero = 0; - int length; - int status = 0; int output_case; char newline; @@ -510,18 +311,18 @@ main(int argc, char *argv[]) newline = flag_zero ? '\0' : '\n'; if (flag_check) { if (!argc) { - status |= -check_and_print("-", length, flag_hex, newline); + status |= -check_and_print("-", (size_t)length, flag_hex, newline); } else { for (; *argv; argv++) - status |= -check_and_print(*argv, length, flag_hex, newline); + status |= -check_and_print(*argv, (size_t)length, flag_hex, newline); } } else { output_case = flag_binary ? -1 : flag_upper; if (!argc) { - status |= -hash_and_print("-", length, flag_hex, newline, output_case); + status |= -hash_and_print("-", (size_t)length, flag_hex, newline, output_case); } else { for (; *argv; argv++) - status |= -hash_and_print(*argv, length, flag_hex, newline, output_case); + status |= -hash_and_print(*argv, (size_t)length, flag_hex, newline, output_case); } } diff --git a/common.c b/common.c new file mode 100644 index 0000000..c389285 --- /dev/null +++ b/common.c @@ -0,0 +1,228 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +void * +erealloc(void *ptr, size_t n) +{ + ptr = realloc(ptr, n); + if (!ptr) { + fprintf(stderr, "%s: %s\n", argv0, strerror(errno)); + exit(2); + } + return ptr; +} + +void * +emalloc(size_t n) +{ + void *ptr = malloc(n); + if (!ptr) { + fprintf(stderr, "%s: %s\n", argv0, strerror(errno)); + exit(2); + } + return ptr; +} + +static int +parse_fd(const char *name) +{ + long int num; + char *end; + if (!isdigit(*name)) + return -1; + errno = 0; + num = strtol(name, &end, 10); + if (num > INT_MAX || *end || errno) + return -1; + return (int)num; +} + +int +open_file(const char *path, int *closep) +{ + int fd = -1; + + *closep = 0; + + if (!strcmp(path, "-")) + fd = STDIN_FILENO; + else if (!strcmp(path, "/dev/stdin")) + fd = STDIN_FILENO; + else if (!strcmp(path, "/dev/stdout")) + fd = STDOUT_FILENO; + else if (!strcmp(path, "/dev/stderr")) + fd = STDERR_FILENO; + else if (!strncmp(path, "/dev/fd/", sizeof("/dev/fd/") - 1)) + fd = parse_fd(&path[sizeof("/dev/fd/") - 1]); + else if (!strncmp(path, "/proc/self/fd/", sizeof("/proc/self/fd/") - 1)) + fd = parse_fd(&path[sizeof("/proc/self/fd/") - 1]); + + if (fd < 0) { + fd = open(path, O_RDONLY); + if (fd < 0) + return -1; + *closep = 1; + } + + return fd; +} + +static int +check_and_print_file(const char *path, size_t hashlen, int decode_hex, char *expected) +{ + unsigned char *hash; + int r, fd, close_fd; + + fd = open_file(path, &close_fd); + if (fd < 0) { + if (errno != ENOENT) + fprintf(stderr, "%s: %s: %s\n", argv0, path, strerror(errno)); + missing: + printf("%s: Missing\n", path); + return -1; + } + + hash = hashlen ? emalloc(hashlen / 8) : NULL; + r = hash_fd(fd, path, decode_hex, hash); + + if (close_fd) + close(fd); + + if (r < 0) { + free(hash); + goto missing; + } + + libblake_decode_hex(expected, hashlen / 4, expected, &(int){0}); + if (!memcmp(hash, expected, hashlen / 8)) { + free(hash); + printf("%s: OK\n", path); + return 0; + } else { + free(hash); + printf("%s: Fail\n", path); + return -1; + } +} + +int +check_and_print(const char *path, size_t hashlen, int decode_hex, char newline) +{ + int fd, close_fd, status = 0; + char *buf = NULL; + size_t size = 0; + size_t len = 0; + ssize_t r; + size_t i, j, k; + + fd = open_file(path, &close_fd); + if (fd < 0) { + fprintf(stderr, "%s: %s: %s\n", argv0, path, strerror(errno)); + exit(2); + } + + for (;;) { + if (len == size) + buf = erealloc(buf, size += 8 << 10); + r = read(fd, &buf[len], size - len); + if (r > 0) { + len += (size_t)r; + } else if (!r) { + break; + } else if (errno == EINTR) { + continue; + } else { + fprintf(stderr, "%s: %s: %s\n", argv0, path, strerror(errno)); + exit(2); + } + } + buf = erealloc(buf, len + 1); + buf[len] = '\0'; + + if (newline) { + for (i = 0; i < len; i = k + 1) { + while (isspace(buf[i])) + i++; + for (j = i; j - i < hashlen / 4; j++) + if (!isxdigit(buf[j])) + goto corrupt; + if (j == len || !isblank(buf[j])) + goto corrupt; + buf[j] = '\0'; + j++; + while (isblank(buf[j])) + j++; + if (!buf[j]) + goto corrupt; + for (k = j; buf[k] && buf[k] != newline;) + k++; + buf[k] = '\0'; + status |= check_and_print_file(&buf[j], hashlen, decode_hex, &buf[i]); + } + } else { + for (i = 0; i < len; i = k + 1) { + for (j = i; j - i < hashlen / 4; j++) + if (!isxdigit(buf[j])) + goto corrupt; + if (buf[j + 0] != ' ' || buf[j + 1] != ' ') + goto corrupt; + buf[j] = '\0'; + j += 2; + k = j + strlen(&buf[j]); + status |= check_and_print_file(&buf[j], hashlen, decode_hex, &buf[i]); + } + } + + if (close_fd) + close(fd); + return status; + +corrupt: + fprintf(stderr, "%s: %s: invalid file content\n", argv0, path); + exit(2); +} + +static int +hash_file(const char *path, int decode_hex, unsigned char hash[]) +{ + int ret, fd, close_fd; + + fd = open_file(path, &close_fd); + if (fd < 0) { + fprintf(stderr, "%s: %s: %s\n", argv0, path, strerror(errno)); + return -1; + } + + ret = hash_fd(fd, path, decode_hex, hash); + + if (close_fd) + close(fd); + return ret; +} + +int +hash_and_print(const char *path, size_t hashlen, int decode_hex, char newline, int output_case) +{ + unsigned char *hash; + char *hex; + + hash = hashlen ? emalloc(hashlen / 8) : 0; + hex = emalloc(hashlen / 4 + 1); + + if (hash_file(path, decode_hex, hash)) { + free(hash); + free(hex); + return -1; + } + + if (output_case < 0) { + fwrite(hash, 1, hashlen / 8, stdout); + } else { + libblake_encode_hex(hash, hashlen / 8, hex, output_case); + printf("%s %s%c", hex, path, newline); + } + + free(hash); + free(hex); + return 0; +} diff --git a/common.h b/common.h index b0cbd63..96998a8 100644 --- a/common.h +++ b/common.h @@ -12,3 +12,13 @@ #include #include "arg.h" + +/* common.c */ +void *erealloc(void *ptr, size_t n); +void *emalloc(size_t n); +int open_file(const char *path, int *closep); +int check_and_print(const char *path, size_t hashlen, int decode_hex, char newline); +int hash_and_print(const char *path, size_t hashlen, int decode_hex, char newline, int output_case); + +/* *sum.c */ +int hash_fd(int fd, const char *fname, int decode_hex, unsigned char hash[]); -- cgit v1.2.3-70-g09d2