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