1 #include "bsdtar_platform.h"
2
3 #include <inttypes.h>
4 #include <stdint.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7
8 #include "humansize.h"
9 #include "storage.h"
10 #include "tarsnap_opt.h"
11 #include "warnp.h"
12
13 #include "chunks_internal.h"
14
15 /**
16 * chunks_stats_zero(stats):
17 * Zero the provided set of statistics.
18 */
19 void
chunks_stats_zero(struct chunkstats * stats)20 chunks_stats_zero(struct chunkstats * stats)
21 {
22
23 stats->nchunks = 0;
24 stats->s_len = 0;
25 stats->s_zlen = 0;
26 }
27
28 /**
29 * chunks_stats_add(stats, len, zlen, copies):
30 * Adjust ${stats} for the addition of ${copies} chunks each having length
31 * ${len} and compressed length ${zlen}.
32 */
33 void
chunks_stats_add(struct chunkstats * stats,size_t len,size_t zlen,ssize_t copies)34 chunks_stats_add(struct chunkstats * stats, size_t len, size_t zlen,
35 ssize_t copies)
36 {
37
38 /*
39 * The value ${copies} may be negative, but since nchunks, s_len, and
40 * s_zlen are all of type uint64_t, casting a negative value to
41 * uint64_t will still yield the correct results, thanks to modulo-2^64
42 * arithmetic.
43 */
44 stats->nchunks += (uint64_t)copies;
45 stats->s_len += (uint64_t)(len) * (uint64_t)(copies);
46 stats->s_zlen += (uint64_t)(zlen) * (uint64_t)(copies);
47 }
48
49 /**
50 * chunks_stats_addstats(to, from):
51 * Add statistics in ${from} to the statistics in ${to}, storing the result
52 * in ${to}.
53 */
54 void
chunks_stats_addstats(struct chunkstats * to,struct chunkstats * from)55 chunks_stats_addstats(struct chunkstats * to, struct chunkstats * from)
56 {
57
58 to->nchunks += from->nchunks;
59 to->s_len += from->s_len;
60 to->s_zlen += from->s_zlen;
61 }
62
63 /**
64 * chunks_stats_printheader(stream, csv):
65 * Print a header line for statistics to ${stream}, optionally in ${csv}
66 * format.
67 */
68 int
chunks_stats_printheader(FILE * stream,int csv)69 chunks_stats_printheader(FILE * stream, int csv)
70 {
71
72 if (csv) {
73 #ifdef STATS_WITH_CHUNKS
74 if (fprintf(stream, "%s,%s,%s,%s\n",
75 "Archive name", "# of chunks", "Total size",
76 "Compressed size") < 0) {
77 #else
78 if (fprintf(stream, "%s,%s,%s\n",
79 "Archive name", "Total size", "Compressed size") < 0) {
80 #endif
81 warnp("fprintf");
82 goto err0;
83 }
84 } else {
85 #ifdef STATS_WITH_CHUNKS
86 if (fprintf(stream, "%-25s %12s %15s %15s\n",
87 "", "# of chunks", "Total size", "Compressed size") < 0) {
88 #else
89 if (fprintf(stream, "%-32s %15s %15s\n",
90 "", "Total size", "Compressed size") < 0) {
91 #endif
92 warnp("fprintf");
93 goto err0;
94 }
95 }
96
97 /* Success! */
98 return (0);
99
100 err0:
101 /* Failure! */
102 return (-1);
103 }
104
105 /**
106 * chunks_stats_print(stream, stats, name, stats_extra, csv):
107 * Print a line with ${name} and combined statistics from ${stats} and
108 * ${stats_extra} to ${stream}, optionally in ${csv} format.
109 */
110 int
111 chunks_stats_print(FILE * stream, struct chunkstats * stats,
112 const char * name, struct chunkstats * stats_extra, int csv)
113 {
114 struct chunkstats s;
115 char * s_lenstr, * s_zlenstr;
116 char * format_string;
117
118 /* Compute sum of stats and stats_extra. */
119 s.nchunks = stats->nchunks + stats_extra->nchunks;
120 s.s_len = stats->s_len + stats_extra->s_len;
121 s.s_zlen = stats->s_zlen + stats_extra->s_zlen;
122
123 /* Stringify values. */
124 if (tarsnap_opt_humanize_numbers) {
125 if ((s_lenstr = humansize(s.s_len)) == NULL)
126 goto err0;
127 if ((s_zlenstr = humansize(s.s_zlen +
128 s.nchunks * STORAGE_FILE_OVERHEAD)) == NULL)
129 goto err1;
130 } else {
131 if (csv)
132 format_string = "%" PRIu64;
133 else
134 format_string = "%15" PRIu64;
135
136 if (asprintf(&s_lenstr, format_string, s.s_len) == -1) {
137 warnp("asprintf");
138 goto err0;
139 }
140 if (asprintf(&s_zlenstr, format_string,
141 s.s_zlen + s.nchunks * STORAGE_FILE_OVERHEAD) == -1) {
142 warnp("asprintf");
143 goto err1;
144 }
145 }
146
147 /* Print output line. */
148 if (csv) {
149 if (fprintf(stream,
150 #ifdef STATS_WITH_CHUNKS
151 "%s,%" PRIu64 ",%s,%s\n",
152 name, s.nchunks,
153 #else
154 "%s,%s,%s\n",
155 name,
156 #endif
157 s_lenstr, s_zlenstr) < 0) {
158 warnp("fprintf");
159 goto err2;
160 }
161 } else {
162 if (fprintf(stream,
163 #ifdef STATS_WITH_CHUNKS
164 "%-25s %12" PRIu64 " %15s %15s\n",
165 name, s.nchunks,
166 #else
167 "%-32s %15s %15s\n",
168 name,
169 #endif
170 s_lenstr, s_zlenstr) < 0) {
171 warnp("fprintf");
172 goto err2;
173 }
174 }
175
176 /* Free strings allocated by asprintf or humansize. */
177 free(s_zlenstr);
178 free(s_lenstr);
179
180 /* Success! */
181 return (0);
182
183 err2:
184 free(s_zlenstr);
185 err1:
186 free(s_lenstr);
187 err0:
188 /* Failure! */
189 return (-1);
190 }
191