diff options
-rw-r--r-- | .gitignore | 8 | ||||
-rw-r--r-- | LICENSE | 15 | ||||
-rw-r--r-- | Makefile | 51 | ||||
-rw-r--r-- | arg.h | 38 | ||||
-rw-r--r-- | b224sum.1 | 68 | ||||
-rw-r--r-- | b256sum.1 | 68 | ||||
-rw-r--r-- | b384sum.1 | 68 | ||||
-rw-r--r-- | b512sum.1 | 68 | ||||
-rw-r--r-- | bsum.1 | 72 | ||||
-rw-r--r-- | bsum.c | 533 | ||||
-rw-r--r-- | common.h | 14 | ||||
-rw-r--r-- | config.mk | 8 |
12 files changed, 1011 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d17d682 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +*\#* +*~ +*.o +*.su +*.gcov +*.gcno +*.gcda +/bsum @@ -0,0 +1,15 @@ +ISC License + +© 2022 Mattias Andrée <maandree@kth.se> + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..3f743a8 --- /dev/null +++ b/Makefile @@ -0,0 +1,51 @@ +.POSIX: + +CONFIGFILE = config.mk +include $(CONFIGFILE) + +OBJ =\ + bsum.o + +HDR =\ + arg.h\ + common.h + +all: bsum +$(OBJ): $(HDR) + +.c.o: + $(CC) -c -o $@ $< $(CFLAGS) $(CPPFLAGS) + +bsum: $(OBJ) + $(CC) -o $@ $(OBJ) $(LDFLAGS) + +install: bsum + mkdir -p -- "$(DESTDIR)$(PREFIX)/bin" + mkdir -p -- "$(DESTDIR)$(MANPREFIX)/man1/" + cp -- bsum "$(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/" + +uninstall: + -rm -f -- "$(DESTDIR)$(PREFIX)/bin/bsum" + -rm -f -- "$(DESTDIR)$(PREFIX)/bin/b224sum" + -rm -f -- "$(DESTDIR)$(PREFIX)/bin/b256sum" + -rm -f -- "$(DESTDIR)$(PREFIX)/bin/b384sum" + -rm -f -- "$(DESTDIR)$(PREFIX)/bin/b512sum" + -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" + +clean: + -rm -f -- *.o *.su *.gcov *.gcno *.gcda + -rm -f -- bsum + +.SUFFIXES: +.SUFFIXES: .o .c + +.PHONY: all install uninstall clean @@ -0,0 +1,38 @@ +/* Trivial code, not subject to copyright, use as you see fit. + * Reimplementation of 20h's arg.h */ + +#ifndef ARG_H +#define ARG_H + +#include <stddef.h> + + +extern const char *argv0; + + +#define ARGBEGIN do {\ + char arg_h_flag_, arg_h_break_;\ + if (!argc)\ + break;\ + argv0 = argv[0];\ + while (--argc, *++argv && argv[0][0] == '-' && argv[0][1]) {\ + if (argv[0][1] == '-' && !argv[0][2]) {\ + argv++;\ + argc--;\ + break;\ + }\ + for (arg_h_break_ = 0; !arg_h_break_ && *++*argv;) {\ + switch ((arg_h_flag_ = **argv)) + +#define ARGEND }\ + }\ + } while (0) + + +#define FLAG() (arg_h_flag_) + +#define ARG() (arg_h_break_ = 1, argv[0][1] ? &argv[0][1] :\ + argv[1] ? (argc--, *++argv) :\ + (usage(), NULL)) + +#endif diff --git a/b224sum.1 b/b224sum.1 new file mode 100644 index 0000000..82c6a48 --- /dev/null +++ b/b224sum.1 @@ -0,0 +1,68 @@ +.TH B224SUM 1 blakesum +.SH NAME +b224sum - Compute and check BLAKE-224 message digests +.SH SYNOPSIS +.B bsum +[-c | -B | -L | -U] [-xz] +.RI [ file "] ..." +.SH DESCRIPTION +Print or check BLAKE-224 checksums. +.SH OPTIONS +The +.B b224sum +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 BLAKE-224 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 <space> or <tab>, or if they +contain a <newline, unless the +.B -z +option is also used. +.TP +.B -L +Output checksums in lower-case hexadecimal representation. (Default) +.TP +.B -U +Output checksums in upper-case hexadecimal representation. +.TP +.B -x +Convert input files from hexadecimal form to binary form +before calculating the checksums. +.TP +.B -z +Lines end with NUL instead of LF. If used with +.BR -c , +this applies to read files (not the output), but it will +also apply more strict parsing and allow any whitespace +in file names. +.SH OPERANDS +The following operands are supported: +.TP +.I file +File to read. The standard input will be used +.B - +or no +.I file +is specified. +.SH EXIT STATUS +.TP +0 +Successful completion. +.TP +1 +Checksums did not match or a file did not exist. +.TP +2 +An error occurred. diff --git a/b256sum.1 b/b256sum.1 new file mode 100644 index 0000000..4998b57 --- /dev/null +++ b/b256sum.1 @@ -0,0 +1,68 @@ +.TH B256SUM 1 blakesum +.SH NAME +b256sum - Compute and check BLAKE-256 message digests +.SH SYNOPSIS +.B bsum +[-c | -B | -L | -U] [-xz] +.RI [ file "] ..." +.SH DESCRIPTION +Print or check BLAKE-256 checksums. +.SH OPTIONS +The +.B b256sum +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 BLAKE-256 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 <space> or <tab>, or if they +contain a <newline, unless the +.B -z +option is also used. +.TP +.B -L +Output checksums in lower-case hexadecimal representation. (Default) +.TP +.B -U +Output checksums in upper-case hexadecimal representation. +.TP +.B -x +Convert input files from hexadecimal form to binary form +before calculating the checksums. +.TP +.B -z +Lines end with NUL instead of LF. If used with +.BR -c , +this applies to read files (not the output), but it will +also apply more strict parsing and allow any whitespace +in file names. +.SH OPERANDS +The following operands are supported: +.TP +.I file +File to read. The standard input will be used +.B - +or no +.I file +is specified. +.SH EXIT STATUS +.TP +0 +Successful completion. +.TP +1 +Checksums did not match or a file did not exist. +.TP +2 +An error occurred. diff --git a/b384sum.1 b/b384sum.1 new file mode 100644 index 0000000..925b698 --- /dev/null +++ b/b384sum.1 @@ -0,0 +1,68 @@ +.TH B384SUM 1 blakesum +.SH NAME +b384sum - Compute and check BLAKE-384 message digests +.SH SYNOPSIS +.B bsum +[-c | -B | -L | -U] [-xz] +.RI [ file "] ..." +.SH DESCRIPTION +Print or check BLAKE-384 checksums. +.SH OPTIONS +The +.B b384sum +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 BLAKE-384 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 <space> or <tab>, or if they +contain a <newline, unless the +.B -z +option is also used. +.TP +.B -L +Output checksums in lower-case hexadecimal representation. (Default) +.TP +.B -U +Output checksums in upper-case hexadecimal representation. +.TP +.B -x +Convert input files from hexadecimal form to binary form +before calculating the checksums. +.TP +.B -z +Lines end with NUL instead of LF. If used with +.BR -c , +this applies to read files (not the output), but it will +also apply more strict parsing and allow any whitespace +in file names. +.SH OPERANDS +The following operands are supported: +.TP +.I file +File to read. The standard input will be used +.B - +or no +.I file +is specified. +.SH EXIT STATUS +.TP +0 +Successful completion. +.TP +1 +Checksums did not match or a file did not exist. +.TP +2 +An error occurred. diff --git a/b512sum.1 b/b512sum.1 new file mode 100644 index 0000000..ebaf844 --- /dev/null +++ b/b512sum.1 @@ -0,0 +1,68 @@ +.TH B512SUM 1 blakesum +.SH NAME +b512sum - Compute and check BLAKE-512 message digests +.SH SYNOPSIS +.B bsum +[-c | -B | -L | -U] [-xz] +.RI [ file "] ..." +.SH DESCRIPTION +Print or check BLAKE-512 checksums. +.SH OPTIONS +The +.B b512sum +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 BLAKE-512 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 <space> or <tab>, or if they +contain a <newline, unless the +.B -z +option is also used. +.TP +.B -L +Output checksums in lower-case hexadecimal representation. (Default) +.TP +.B -U +Output checksums in upper-case hexadecimal representation. +.TP +.B -x +Convert input files from hexadecimal form to binary form +before calculating the checksums. +.TP +.B -z +Lines end with NUL instead of LF. If used with +.BR -c , +this applies to read files (not the output), but it will +also apply more strict parsing and allow any whitespace +in file names. +.SH OPERANDS +The following operands are supported: +.TP +.I file +File to read. The standard input will be used +.B - +or no +.I file +is specified. +.SH EXIT STATUS +.TP +0 +Successful completion. +.TP +1 +Checksums did not match or a file did not exist. +.TP +2 +An error occurred. @@ -0,0 +1,72 @@ +.TH BSUM 1 blakesum +.SH NAME +bsum - Compute and check BLAKE message digests +.SH SYNOPSIS +.B bsum +[-l bits] [-c | -B | -L | -U] [-xz] +.RI [ file "] ..." +.SH DESCRIPTION +Print or check BLAKE checksums. +.SH OPTIONS +The +.B bsum +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 BLAKE 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 <space> or <tab>, or if they +contain a <newline, unless the +.B -z +option is also used. +.TP +.B -L +Output checksums in lower-case hexadecimal representation. (Default) +.TP +.B -l +Select version of the BLAKE algorithm. Valid values +are 224 (default), 256, 384, and 512. +.TP +.B -U +Output checksums in upper-case hexadecimal representation. +.TP +.B -x +Convert input files from hexadecimal form to binary form +before calculating the checksums. +.TP +.B -z +Lines end with NUL instead of LF. If used with +.BR -c , +this applies to read files (not the output), but it will +also apply more strict parsing and allow any whitespace +in file names. +.SH OPERANDS +The following operands are supported: +.TP +.I file +File to read. The standard input will be used +.B - +or no +.I file +is specified. +.SH EXIT STATUS +.TP +0 +Successful completion. +.TP +1 +Checksums did not match or a file did not exist. +.TP +2 +An error occurred. @@ -0,0 +1,533 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +const char *argv0 = "bsum"; + +static int lenght_by_command_name = 0; + +static void +usage(void) +{ + fprintf(stderr, "usage: %s%s [-c | -B | -L | -U] [-xz] [file] ...", + argv0, lenght_by_command_name ? "" : " [-l bits]"); + 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")) { + lenght_by_command_name = 224; + } else if (strstr(p, "b256sum")) { + lenght_by_command_name = 256; + } else if (strstr(p, "b384sum")) { + lenght_by_command_name = 384; + } 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) +{ + struct libblake_blake224_state state; + char *buf = NULL; + size_t size = 0; + size_t len = 0; + size_t off = 0; + size_t req; + ssize_t r; + int ok; + libblake_blake224_init(&state); + 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)); + return -1; + } + len += (size_t)r; + if (!decode_hex) { + off += libblake_blake224_update(&state, &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"); + return -1; + } + } + req = libblake_blake224_digest_get_required_input_size(len, 0, NULL); + 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) +{ + struct libblake_blake256_state state; + char *buf = NULL; + size_t size = 0; + size_t len = 0; + size_t off = 0; + size_t req; + ssize_t r; + int ok; + libblake_blake256_init(&state); + 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)); + return -1; + } + len += (size_t)r; + if (!decode_hex) { + off += libblake_blake256_update(&state, &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"); + return -1; + } + } + req = libblake_blake256_digest_get_required_input_size(len, 0, NULL); + 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) +{ + struct libblake_blake384_state state; + char *buf = NULL; + size_t size = 0; + size_t len = 0; + size_t off = 0; + size_t req; + ssize_t r; + int ok; + libblake_blake384_init(&state); + 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)); + return -1; + } + len += (size_t)r; + if (!decode_hex) { + off += libblake_blake384_update(&state, &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"); + return -1; + } + } + req = libblake_blake384_digest_get_required_input_size(len, 0, NULL); + 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) +{ + struct libblake_blake512_state state; + char *buf = NULL; + size_t size = 0; + size_t len = 0; + size_t off = 0; + size_t req; + ssize_t r; + int ok; + libblake_blake512_init(&state); + 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)); + return -1; + } + len += (size_t)r; + if (!decode_hex) { + off += libblake_blake512_update(&state, &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"); + return -1; + } + } + req = libblake_blake512_digest_get_required_input_size(len, 0, NULL); + 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 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; + } + + if (length == 224) + ret = hash_file_blake224(fd, path, decode_hex, hash, hash_lenp); + else if (length == 256) + ret = hash_file_blake256(fd, path, decode_hex, hash, hash_lenp); + else if (length == 384) + ret = hash_file_blake384(fd, path, decode_hex, hash, hash_lenp); + else if (length == 512) + ret = hash_file_blake512(fd, path, decode_hex, hash, hash_lenp); + 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; + + if (argv[0]) + get_lenght_by_command_name(argv[0]); + + length = lenght_by_command_name; + + 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 'x': + flag_hex = 1; + break; + case 'z': + flag_zero = 1; + break; + case 'l': + if (length) + usage(); + length = atoi(ARG()); + if (length != 224 && length != 256 && length != 384 && length != 512) { + fprintf(stderr, "%s: valid arguments for -l are 224 (default), 256, 384, and 512\n", argv0); + return 2; + } + break; + default: + usage(); + } ARGEND; + + if (flag_check + flag_binary + flag_lower + flag_upper > 1) + usage(); + + if (!length) + length = 224; + + newline = flag_zero ? '\0' : '\n'; + if (flag_check) { + if (!argc) { + status |= -check_and_print("-", length, flag_hex, newline); + } else { + for (; *argv; argv++) + status |= -check_and_print(*argv, length, flag_hex, newline); + } + } else { + output_case = flag_binary ? -1 : flag_upper; + if (!argc) { + status |= -hash_and_print("-", length, flag_hex, newline, output_case); + } else { + for (; *argv; argv++) + status |= -hash_and_print(*argv, length, 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/common.h b/common.h new file mode 100644 index 0000000..b0cbd63 --- /dev/null +++ b/common.h @@ -0,0 +1,14 @@ +/* See LICENSE file for copyright and license details. */ +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <unistd.h> + +#include <libblake.h> + +#include "arg.h" diff --git a/config.mk b/config.mk new file mode 100644 index 0000000..5656df1 --- /dev/null +++ b/config.mk @@ -0,0 +1,8 @@ +PREFIX = /usr +MANPREFIX = $(PREFIX)/share/man + +CC = c99 + +CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_GNU_SOURCE +CFLAGS = -Wall -O3 +LDFLAGS = -s -lblake |