aboutsummaryrefslogtreecommitdiffstats
path: root/common.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--common.c228
1 files changed, 228 insertions, 0 deletions
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;
+}