Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/tests/sys/fs/tarfs/tarsum.c
39537 views
1
/*-
2
* Copyright (c) 2024 Klara, Inc.
3
*
4
* SPDX-License-Identifier: BSD-2-Clause
5
*
6
* This program reads a tarball from stdin, recalculates the checksums of
7
* all ustar records within it, and writes the result to stdout.
8
*/
9
10
#include <err.h>
11
#include <stdarg.h>
12
#include <stdbool.h>
13
#include <stdint.h>
14
#include <stdio.h>
15
#include <stdlib.h>
16
#include <string.h>
17
#include <unistd.h>
18
19
static bool opt_v;
20
21
static int
22
verbose(const char *fmt, ...)
23
{
24
va_list ap;
25
int ret;
26
27
if (!opt_v)
28
return (0);
29
va_start(ap, fmt);
30
ret = vfprintf(stderr, fmt, ap);
31
va_end(ap);
32
return (ret);
33
}
34
35
static void
36
tarsum(FILE *in, const char *ifn, FILE *out, const char *ofn)
37
{
38
union {
39
uint8_t bytes[512];
40
struct {
41
uint8_t prelude[148];
42
char checksum[8];
43
uint8_t interlude[101];
44
char magic[6];
45
char version[2];
46
char postlude[];
47
};
48
} ustar;
49
unsigned long sum;
50
off_t offset = 0;
51
ssize_t ret;
52
size_t i;
53
54
for (;;) {
55
if ((ret = fread(&ustar, 1, sizeof(ustar), in)) < 0)
56
err(1, "%s", ifn);
57
else if (ret == 0)
58
break;
59
else if ((size_t)ret < sizeof(ustar))
60
errx(1, "%s: Short read", ifn);
61
if (strcmp(ustar.magic, "ustar") == 0 &&
62
ustar.version[0] == '0' && ustar.version[1] == '0') {
63
verbose("header found at offset %#lx\n", offset);
64
verbose("current checksum %.*s\n",
65
(int)sizeof(ustar.checksum), ustar.checksum);
66
memset(ustar.checksum, ' ', sizeof(ustar.checksum));
67
for (sum = i = 0; i < sizeof(ustar); i++)
68
sum += ustar.bytes[i];
69
verbose("calculated checksum %#lo\n", sum);
70
sprintf(ustar.checksum, "%#lo", sum);
71
}
72
if ((ret = fwrite(&ustar, 1, sizeof(ustar), out)) < 0)
73
err(1, "%s", ofn);
74
else if ((size_t)ret < sizeof(ustar))
75
errx(1, "%s: Short write", ofn);
76
offset += sizeof(ustar);
77
}
78
verbose("%lu bytes processed\n", offset);
79
}
80
81
static void
82
usage(void)
83
{
84
fprintf(stderr, "usage: tarsum [-v] [-o output] [input]\n");
85
exit(1);
86
}
87
88
int
89
main(int argc, char *argv[])
90
{
91
const char *ifn, *ofn = NULL;
92
FILE *in, *out;
93
int opt;
94
95
while ((opt = getopt(argc, argv, "o:v")) != -1) {
96
switch (opt) {
97
case 'o':
98
ofn = optarg;
99
break;
100
case 'v':
101
opt_v = true;
102
break;
103
default:
104
usage();
105
}
106
}
107
argc -= optind;
108
argv += optind;
109
if (argc == 0 || strcmp(*argv, "-") == 0) {
110
ifn = "stdin";
111
in = stdin;
112
} else if (argc == 1) {
113
ifn = *argv;
114
if ((in = fopen(ifn, "rb")) == NULL)
115
err(1, "%s", ifn);
116
} else {
117
usage();
118
}
119
if (ofn == NULL || strcmp(ofn, "-") == 0) {
120
ofn = "stdout";
121
out = stdout;
122
} else {
123
if ((out = fopen(ofn, "wb")) == NULL)
124
err(1, "%s", ofn);
125
}
126
tarsum(in, ifn, out, ofn);
127
return (0);
128
}
129
130