diff options
Diffstat (limited to 'tests/sys/fs/tarfs/tarsum.c')
| -rw-r--r-- | tests/sys/fs/tarfs/tarsum.c | 128 |
1 files changed, 128 insertions, 0 deletions
diff --git a/tests/sys/fs/tarfs/tarsum.c b/tests/sys/fs/tarfs/tarsum.c new file mode 100644 index 000000000000..73ead2230a5e --- /dev/null +++ b/tests/sys/fs/tarfs/tarsum.c @@ -0,0 +1,128 @@ +/*- + * Copyright (c) 2024 Klara, Inc. + * + * SPDX-License-Identifier: BSD-2-Clause + * + * This program reads a tarball from stdin, recalculates the checksums of + * all ustar records within it, and writes the result to stdout. + */ + +#include <err.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +static bool opt_v; + +static int +verbose(const char *fmt, ...) +{ + va_list ap; + int ret; + + if (!opt_v) + return (0); + va_start(ap, fmt); + ret = vfprintf(stderr, fmt, ap); + va_end(ap); + return (ret); +} + +static void +tarsum(FILE *in, const char *ifn, FILE *out, const char *ofn) +{ + union { + uint8_t bytes[512]; + struct { + uint8_t prelude[148]; + char checksum[8]; + uint8_t interlude[101]; + char magic[6]; + char version[2]; + char postlude[]; + }; + } ustar; + unsigned long sum; + off_t offset = 0; + ssize_t ret; + size_t i; + + for (;;) { + if ((ret = fread(&ustar, 1, sizeof(ustar), in)) < 0) + err(1, "%s", ifn); + else if (ret == 0) + break; + else if ((size_t)ret < sizeof(ustar)) + errx(1, "%s: Short read", ifn); + if (strcmp(ustar.magic, "ustar") == 0 && + ustar.version[0] == '0' && ustar.version[1] == '0') { + verbose("header found at offset %#lx\n", offset); + verbose("current checksum %.*s\n", + (int)sizeof(ustar.checksum), ustar.checksum); + memset(ustar.checksum, ' ', sizeof(ustar.checksum)); + for (sum = i = 0; i < sizeof(ustar); i++) + sum += ustar.bytes[i]; + verbose("calculated checksum %#lo\n", sum); + sprintf(ustar.checksum, "%#lo", sum); + } + if ((ret = fwrite(&ustar, 1, sizeof(ustar), out)) < 0) + err(1, "%s", ofn); + else if ((size_t)ret < sizeof(ustar)) + errx(1, "%s: Short write", ofn); + offset += sizeof(ustar); + } + verbose("%lu bytes processed\n", offset); +} + +static void +usage(void) +{ + fprintf(stderr, "usage: tarsum [-v] [-o output] [input]\n"); + exit(1); +} + +int +main(int argc, char *argv[]) +{ + const char *ifn, *ofn = NULL; + FILE *in, *out; + int opt; + + while ((opt = getopt(argc, argv, "o:v")) != -1) { + switch (opt) { + case 'o': + ofn = optarg; + break; + case 'v': + opt_v = true; + break; + default: + usage(); + } + } + argc -= optind; + argv += optind; + if (argc == 0 || strcmp(*argv, "-") == 0) { + ifn = "stdin"; + in = stdin; + } else if (argc == 1) { + ifn = *argv; + if ((in = fopen(ifn, "rb")) == NULL) + err(1, "%s", ifn); + } else { + usage(); + } + if (ofn == NULL || strcmp(ofn, "-") == 0) { + ofn = "stdout"; + out = stdout; + } else { + if ((out = fopen(ofn, "wb")) == NULL) + err(1, "%s", ofn); + } + tarsum(in, ifn, out, ofn); + return (0); +} |
