1 /*
2 * checksum.c - Adler-32 and CRC-32 checksumming program
3 *
4 * Copyright 2016 Eric Biggers
5 *
6 * Permission is hereby granted, free of charge, to any person
7 * obtaining a copy of this software and associated documentation
8 * files (the "Software"), to deal in the Software without
9 * restriction, including without limitation the rights to use,
10 * copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following
13 * conditions:
14 *
15 * The above copyright notice and this permission notice shall be
16 * included in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 * OTHER DEALINGS IN THE SOFTWARE.
26 */
27
28 #include <zlib.h>
29
30 #include "prog_util.h"
31
32 static const tchar *const optstring = T("Ahs:tZ");
33
34 static void
show_usage(FILE * fp)35 show_usage(FILE *fp)
36 {
37 fprintf(fp,
38 "Usage: %"TS" [-A] [-h] [-s SIZE] [-t] [-Z] [FILE]...\n"
39 "Calculate Adler-32 or CRC-32 checksums of the specified FILEs.\n"
40 "\n"
41 "Options:\n"
42 " -A use Adler-32 (default is CRC-32)\n"
43 " -h print this help\n"
44 " -s SIZE chunk size\n"
45 " -t show checksum speed, excluding I/O\n"
46 " -Z use zlib implementation instead of libdeflate\n",
47 program_invocation_name);
48 }
49
50 static u32
zlib_adler32(u32 adler,const void * buf,size_t len)51 zlib_adler32(u32 adler, const void *buf, size_t len)
52 {
53 return adler32(adler, buf, len);
54 }
55
56 static u32
zlib_crc32(u32 crc,const void * buf,size_t len)57 zlib_crc32(u32 crc, const void *buf, size_t len)
58 {
59 return crc32(crc, buf, len);
60 }
61
62 typedef u32 (*cksum_fn_t)(u32, const void *, size_t);
63
64 static int
checksum_stream(struct file_stream * in,cksum_fn_t cksum,u32 * sum,void * buf,size_t bufsize,u64 * size_ret,u64 * elapsed_ret)65 checksum_stream(struct file_stream *in, cksum_fn_t cksum, u32 *sum,
66 void *buf, size_t bufsize, u64 *size_ret, u64 *elapsed_ret)
67 {
68 u64 size = 0;
69 u64 elapsed = 0;
70
71 for (;;) {
72 ssize_t ret;
73 u64 start_time;
74
75 ret = xread(in, buf, bufsize);
76 if (ret < 0)
77 return ret;
78 if (ret == 0)
79 break;
80
81 size += ret;
82 start_time = timer_ticks();
83 *sum = cksum(*sum, buf, ret);
84 elapsed += timer_ticks() - start_time;
85 }
86
87 if (elapsed == 0)
88 elapsed = 1;
89 *size_ret = size;
90 *elapsed_ret = elapsed;
91 return 0;
92 }
93
94 int
tmain(int argc,tchar * argv[])95 tmain(int argc, tchar *argv[])
96 {
97 bool use_adler32 = false;
98 bool use_zlib_impl = false;
99 bool do_timing = false;
100 void *buf;
101 size_t bufsize = 131072;
102 tchar *default_file_list[] = { NULL };
103 cksum_fn_t cksum;
104 int opt_char;
105 int i;
106 int ret;
107
108 program_invocation_name = get_filename(argv[0]);
109
110 while ((opt_char = tgetopt(argc, argv, optstring)) != -1) {
111 switch (opt_char) {
112 case 'A':
113 use_adler32 = true;
114 break;
115 case 'h':
116 show_usage(stdout);
117 return 0;
118 case 's':
119 bufsize = tstrtoul(toptarg, NULL, 10);
120 if (bufsize == 0) {
121 msg("invalid chunk size: \"%"TS"\"", toptarg);
122 return 1;
123 }
124 break;
125 case 't':
126 do_timing = true;
127 break;
128 case 'Z':
129 use_zlib_impl = true;
130 break;
131 default:
132 show_usage(stderr);
133 return 1;
134 }
135 }
136
137 argc -= toptind;
138 argv += toptind;
139
140 if (use_adler32) {
141 if (use_zlib_impl)
142 cksum = zlib_adler32;
143 else
144 cksum = libdeflate_adler32;
145 } else {
146 if (use_zlib_impl)
147 cksum = zlib_crc32;
148 else
149 cksum = libdeflate_crc32;
150 }
151
152 buf = xmalloc(bufsize);
153 if (buf == NULL)
154 return 1;
155
156 if (argc == 0) {
157 argv = default_file_list;
158 argc = ARRAY_LEN(default_file_list);
159 } else {
160 for (i = 0; i < argc; i++)
161 if (argv[i][0] == '-' && argv[i][1] == '\0')
162 argv[i] = NULL;
163 }
164
165 for (i = 0; i < argc; i++) {
166 struct file_stream in;
167 u32 sum = cksum(0, NULL, 0);
168 u64 size = 0;
169 u64 elapsed = 0;
170
171 ret = xopen_for_read(argv[i], true, &in);
172 if (ret != 0)
173 goto out;
174
175 ret = checksum_stream(&in, cksum, &sum, buf, bufsize,
176 &size, &elapsed);
177 if (ret == 0) {
178 if (do_timing) {
179 printf("%08"PRIx32"\t%"TS"\t"
180 "%"PRIu64" ms\t%"PRIu64" MB/s\n",
181 sum, in.name, timer_ticks_to_ms(elapsed),
182 timer_MB_per_s(size, elapsed));
183 } else {
184 printf("%08"PRIx32"\t%"TS"\t\n", sum, in.name);
185 }
186 }
187
188 xclose(&in);
189
190 if (ret != 0)
191 goto out;
192 }
193 ret = 0;
194 out:
195 free(buf);
196 return -ret;
197 }
198