aboutsummaryrefslogtreecommitdiff
path: root/tests/sys/fs/tarfs/tarsum.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/sys/fs/tarfs/tarsum.c')
-rw-r--r--tests/sys/fs/tarfs/tarsum.c128
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);
+}