1*8fb009dcSAndroid Build Coastguard Worker /* Copyright (c) 2014, Google Inc.
2*8fb009dcSAndroid Build Coastguard Worker *
3*8fb009dcSAndroid Build Coastguard Worker * Permission to use, copy, modify, and/or distribute this software for any
4*8fb009dcSAndroid Build Coastguard Worker * purpose with or without fee is hereby granted, provided that the above
5*8fb009dcSAndroid Build Coastguard Worker * copyright notice and this permission notice appear in all copies.
6*8fb009dcSAndroid Build Coastguard Worker *
7*8fb009dcSAndroid Build Coastguard Worker * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8*8fb009dcSAndroid Build Coastguard Worker * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9*8fb009dcSAndroid Build Coastguard Worker * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10*8fb009dcSAndroid Build Coastguard Worker * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11*8fb009dcSAndroid Build Coastguard Worker * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12*8fb009dcSAndroid Build Coastguard Worker * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13*8fb009dcSAndroid Build Coastguard Worker * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
14*8fb009dcSAndroid Build Coastguard Worker
15*8fb009dcSAndroid Build Coastguard Worker #include <openssl/base.h>
16*8fb009dcSAndroid Build Coastguard Worker
17*8fb009dcSAndroid Build Coastguard Worker #include <memory>
18*8fb009dcSAndroid Build Coastguard Worker #include <string>
19*8fb009dcSAndroid Build Coastguard Worker #include <vector>
20*8fb009dcSAndroid Build Coastguard Worker
21*8fb009dcSAndroid Build Coastguard Worker #include <errno.h>
22*8fb009dcSAndroid Build Coastguard Worker #include <fcntl.h>
23*8fb009dcSAndroid Build Coastguard Worker #include <limits.h>
24*8fb009dcSAndroid Build Coastguard Worker #include <stdio.h>
25*8fb009dcSAndroid Build Coastguard Worker #include <sys/stat.h>
26*8fb009dcSAndroid Build Coastguard Worker #include <sys/types.h>
27*8fb009dcSAndroid Build Coastguard Worker
28*8fb009dcSAndroid Build Coastguard Worker #if !defined(OPENSSL_WINDOWS)
29*8fb009dcSAndroid Build Coastguard Worker #include <string.h>
30*8fb009dcSAndroid Build Coastguard Worker #include <unistd.h>
31*8fb009dcSAndroid Build Coastguard Worker #if !defined(O_BINARY)
32*8fb009dcSAndroid Build Coastguard Worker #define O_BINARY 0
33*8fb009dcSAndroid Build Coastguard Worker #endif
34*8fb009dcSAndroid Build Coastguard Worker #else
35*8fb009dcSAndroid Build Coastguard Worker OPENSSL_MSVC_PRAGMA(warning(push, 3))
36*8fb009dcSAndroid Build Coastguard Worker #include <windows.h>
37*8fb009dcSAndroid Build Coastguard Worker OPENSSL_MSVC_PRAGMA(warning(pop))
38*8fb009dcSAndroid Build Coastguard Worker #include <io.h>
39*8fb009dcSAndroid Build Coastguard Worker #if !defined(PATH_MAX)
40*8fb009dcSAndroid Build Coastguard Worker #define PATH_MAX MAX_PATH
41*8fb009dcSAndroid Build Coastguard Worker #endif
42*8fb009dcSAndroid Build Coastguard Worker #endif
43*8fb009dcSAndroid Build Coastguard Worker
44*8fb009dcSAndroid Build Coastguard Worker #include <openssl/digest.h>
45*8fb009dcSAndroid Build Coastguard Worker
46*8fb009dcSAndroid Build Coastguard Worker #include "internal.h"
47*8fb009dcSAndroid Build Coastguard Worker
48*8fb009dcSAndroid Build Coastguard Worker
49*8fb009dcSAndroid Build Coastguard Worker // Source is an awkward expression of a union type in C++: Stdin | File filename.
50*8fb009dcSAndroid Build Coastguard Worker struct Source {
51*8fb009dcSAndroid Build Coastguard Worker enum Type {
52*8fb009dcSAndroid Build Coastguard Worker STDIN,
53*8fb009dcSAndroid Build Coastguard Worker };
54*8fb009dcSAndroid Build Coastguard Worker
SourceSource55*8fb009dcSAndroid Build Coastguard Worker Source() : is_stdin_(false) {}
SourceSource56*8fb009dcSAndroid Build Coastguard Worker explicit Source(Type) : is_stdin_(true) {}
SourceSource57*8fb009dcSAndroid Build Coastguard Worker explicit Source(const std::string &name)
58*8fb009dcSAndroid Build Coastguard Worker : is_stdin_(false), filename_(name) {}
59*8fb009dcSAndroid Build Coastguard Worker
is_stdinSource60*8fb009dcSAndroid Build Coastguard Worker bool is_stdin() const { return is_stdin_; }
filenameSource61*8fb009dcSAndroid Build Coastguard Worker const std::string &filename() const { return filename_; }
62*8fb009dcSAndroid Build Coastguard Worker
63*8fb009dcSAndroid Build Coastguard Worker private:
64*8fb009dcSAndroid Build Coastguard Worker bool is_stdin_;
65*8fb009dcSAndroid Build Coastguard Worker std::string filename_;
66*8fb009dcSAndroid Build Coastguard Worker };
67*8fb009dcSAndroid Build Coastguard Worker
68*8fb009dcSAndroid Build Coastguard Worker static const char kStdinName[] = "standard input";
69*8fb009dcSAndroid Build Coastguard Worker
70*8fb009dcSAndroid Build Coastguard Worker // OpenFile opens the regular file named |filename| and returns a file
71*8fb009dcSAndroid Build Coastguard Worker // descriptor to it.
OpenFile(const std::string & filename)72*8fb009dcSAndroid Build Coastguard Worker static ScopedFD OpenFile(const std::string &filename) {
73*8fb009dcSAndroid Build Coastguard Worker ScopedFD fd = OpenFD(filename.c_str(), O_RDONLY | O_BINARY);
74*8fb009dcSAndroid Build Coastguard Worker if (!fd) {
75*8fb009dcSAndroid Build Coastguard Worker fprintf(stderr, "Failed to open input file '%s': %s\n", filename.c_str(),
76*8fb009dcSAndroid Build Coastguard Worker strerror(errno));
77*8fb009dcSAndroid Build Coastguard Worker return ScopedFD();
78*8fb009dcSAndroid Build Coastguard Worker }
79*8fb009dcSAndroid Build Coastguard Worker
80*8fb009dcSAndroid Build Coastguard Worker #if !defined(OPENSSL_WINDOWS)
81*8fb009dcSAndroid Build Coastguard Worker struct stat st;
82*8fb009dcSAndroid Build Coastguard Worker if (fstat(fd.get(), &st)) {
83*8fb009dcSAndroid Build Coastguard Worker fprintf(stderr, "Failed to stat input file '%s': %s\n", filename.c_str(),
84*8fb009dcSAndroid Build Coastguard Worker strerror(errno));
85*8fb009dcSAndroid Build Coastguard Worker return ScopedFD();
86*8fb009dcSAndroid Build Coastguard Worker }
87*8fb009dcSAndroid Build Coastguard Worker
88*8fb009dcSAndroid Build Coastguard Worker if (!S_ISREG(st.st_mode)) {
89*8fb009dcSAndroid Build Coastguard Worker fprintf(stderr, "%s: not a regular file\n", filename.c_str());
90*8fb009dcSAndroid Build Coastguard Worker return ScopedFD();
91*8fb009dcSAndroid Build Coastguard Worker }
92*8fb009dcSAndroid Build Coastguard Worker #endif
93*8fb009dcSAndroid Build Coastguard Worker
94*8fb009dcSAndroid Build Coastguard Worker return fd;
95*8fb009dcSAndroid Build Coastguard Worker }
96*8fb009dcSAndroid Build Coastguard Worker
97*8fb009dcSAndroid Build Coastguard Worker // SumFile hashes the contents of |source| with |md| and sets |*out_hex| to the
98*8fb009dcSAndroid Build Coastguard Worker // hex-encoded result.
99*8fb009dcSAndroid Build Coastguard Worker //
100*8fb009dcSAndroid Build Coastguard Worker // It returns true on success or prints an error to stderr and returns false on
101*8fb009dcSAndroid Build Coastguard Worker // error.
SumFile(std::string * out_hex,const EVP_MD * md,const Source & source)102*8fb009dcSAndroid Build Coastguard Worker static bool SumFile(std::string *out_hex, const EVP_MD *md,
103*8fb009dcSAndroid Build Coastguard Worker const Source &source) {
104*8fb009dcSAndroid Build Coastguard Worker ScopedFD scoped_fd;
105*8fb009dcSAndroid Build Coastguard Worker int fd;
106*8fb009dcSAndroid Build Coastguard Worker
107*8fb009dcSAndroid Build Coastguard Worker if (source.is_stdin()) {
108*8fb009dcSAndroid Build Coastguard Worker fd = 0;
109*8fb009dcSAndroid Build Coastguard Worker } else {
110*8fb009dcSAndroid Build Coastguard Worker scoped_fd = OpenFile(source.filename());
111*8fb009dcSAndroid Build Coastguard Worker if (!scoped_fd) {
112*8fb009dcSAndroid Build Coastguard Worker return false;
113*8fb009dcSAndroid Build Coastguard Worker }
114*8fb009dcSAndroid Build Coastguard Worker fd = scoped_fd.get();
115*8fb009dcSAndroid Build Coastguard Worker }
116*8fb009dcSAndroid Build Coastguard Worker
117*8fb009dcSAndroid Build Coastguard Worker static const size_t kBufSize = 8192;
118*8fb009dcSAndroid Build Coastguard Worker auto buf = std::make_unique<uint8_t[]>(kBufSize);
119*8fb009dcSAndroid Build Coastguard Worker
120*8fb009dcSAndroid Build Coastguard Worker bssl::ScopedEVP_MD_CTX ctx;
121*8fb009dcSAndroid Build Coastguard Worker if (!EVP_DigestInit_ex(ctx.get(), md, NULL)) {
122*8fb009dcSAndroid Build Coastguard Worker fprintf(stderr, "Failed to initialize EVP_MD_CTX.\n");
123*8fb009dcSAndroid Build Coastguard Worker return false;
124*8fb009dcSAndroid Build Coastguard Worker }
125*8fb009dcSAndroid Build Coastguard Worker
126*8fb009dcSAndroid Build Coastguard Worker for (;;) {
127*8fb009dcSAndroid Build Coastguard Worker size_t n;
128*8fb009dcSAndroid Build Coastguard Worker if (!ReadFromFD(fd, &n, buf.get(), kBufSize)) {
129*8fb009dcSAndroid Build Coastguard Worker fprintf(stderr, "Failed to read from %s: %s\n",
130*8fb009dcSAndroid Build Coastguard Worker source.is_stdin() ? kStdinName : source.filename().c_str(),
131*8fb009dcSAndroid Build Coastguard Worker strerror(errno));
132*8fb009dcSAndroid Build Coastguard Worker return false;
133*8fb009dcSAndroid Build Coastguard Worker }
134*8fb009dcSAndroid Build Coastguard Worker
135*8fb009dcSAndroid Build Coastguard Worker if (n == 0) {
136*8fb009dcSAndroid Build Coastguard Worker break;
137*8fb009dcSAndroid Build Coastguard Worker }
138*8fb009dcSAndroid Build Coastguard Worker
139*8fb009dcSAndroid Build Coastguard Worker if (!EVP_DigestUpdate(ctx.get(), buf.get(), n)) {
140*8fb009dcSAndroid Build Coastguard Worker fprintf(stderr, "Failed to update hash.\n");
141*8fb009dcSAndroid Build Coastguard Worker return false;
142*8fb009dcSAndroid Build Coastguard Worker }
143*8fb009dcSAndroid Build Coastguard Worker }
144*8fb009dcSAndroid Build Coastguard Worker
145*8fb009dcSAndroid Build Coastguard Worker uint8_t digest[EVP_MAX_MD_SIZE];
146*8fb009dcSAndroid Build Coastguard Worker unsigned digest_len;
147*8fb009dcSAndroid Build Coastguard Worker if (!EVP_DigestFinal_ex(ctx.get(), digest, &digest_len)) {
148*8fb009dcSAndroid Build Coastguard Worker fprintf(stderr, "Failed to finish hash.\n");
149*8fb009dcSAndroid Build Coastguard Worker return false;
150*8fb009dcSAndroid Build Coastguard Worker }
151*8fb009dcSAndroid Build Coastguard Worker
152*8fb009dcSAndroid Build Coastguard Worker char hex_digest[EVP_MAX_MD_SIZE * 2];
153*8fb009dcSAndroid Build Coastguard Worker static const char kHextable[] = "0123456789abcdef";
154*8fb009dcSAndroid Build Coastguard Worker for (unsigned i = 0; i < digest_len; i++) {
155*8fb009dcSAndroid Build Coastguard Worker const uint8_t b = digest[i];
156*8fb009dcSAndroid Build Coastguard Worker hex_digest[i * 2] = kHextable[b >> 4];
157*8fb009dcSAndroid Build Coastguard Worker hex_digest[i * 2 + 1] = kHextable[b & 0xf];
158*8fb009dcSAndroid Build Coastguard Worker }
159*8fb009dcSAndroid Build Coastguard Worker *out_hex = std::string(hex_digest, digest_len * 2);
160*8fb009dcSAndroid Build Coastguard Worker
161*8fb009dcSAndroid Build Coastguard Worker return true;
162*8fb009dcSAndroid Build Coastguard Worker }
163*8fb009dcSAndroid Build Coastguard Worker
164*8fb009dcSAndroid Build Coastguard Worker // PrintFileSum hashes |source| with |md| and prints a line to stdout in the
165*8fb009dcSAndroid Build Coastguard Worker // format of the coreutils *sum utilities. It returns true on success or prints
166*8fb009dcSAndroid Build Coastguard Worker // an error to stderr and returns false on error.
PrintFileSum(const EVP_MD * md,const Source & source)167*8fb009dcSAndroid Build Coastguard Worker static bool PrintFileSum(const EVP_MD *md, const Source &source) {
168*8fb009dcSAndroid Build Coastguard Worker std::string hex_digest;
169*8fb009dcSAndroid Build Coastguard Worker if (!SumFile(&hex_digest, md, source)) {
170*8fb009dcSAndroid Build Coastguard Worker return false;
171*8fb009dcSAndroid Build Coastguard Worker }
172*8fb009dcSAndroid Build Coastguard Worker
173*8fb009dcSAndroid Build Coastguard Worker // TODO: When given "--binary" or "-b", we should print " *" instead of " "
174*8fb009dcSAndroid Build Coastguard Worker // between the digest and the filename.
175*8fb009dcSAndroid Build Coastguard Worker //
176*8fb009dcSAndroid Build Coastguard Worker // MSYS and Cygwin md5sum default to binary mode by default, whereas other
177*8fb009dcSAndroid Build Coastguard Worker // platforms' tools default to text mode by default. We default to text mode
178*8fb009dcSAndroid Build Coastguard Worker // by default and consider text mode equivalent to binary mode (i.e. we
179*8fb009dcSAndroid Build Coastguard Worker // always use Unix semantics, even on Windows), which means that our default
180*8fb009dcSAndroid Build Coastguard Worker // output will differ from the MSYS and Cygwin tools' default output.
181*8fb009dcSAndroid Build Coastguard Worker printf("%s %s\n", hex_digest.c_str(),
182*8fb009dcSAndroid Build Coastguard Worker source.is_stdin() ? "-" : source.filename().c_str());
183*8fb009dcSAndroid Build Coastguard Worker return true;
184*8fb009dcSAndroid Build Coastguard Worker }
185*8fb009dcSAndroid Build Coastguard Worker
186*8fb009dcSAndroid Build Coastguard Worker // CheckModeArguments contains arguments for the check mode. See the
187*8fb009dcSAndroid Build Coastguard Worker // sha256sum(1) man page for details.
188*8fb009dcSAndroid Build Coastguard Worker struct CheckModeArguments {
189*8fb009dcSAndroid Build Coastguard Worker bool quiet = false;
190*8fb009dcSAndroid Build Coastguard Worker bool status = false;
191*8fb009dcSAndroid Build Coastguard Worker bool warn = false;
192*8fb009dcSAndroid Build Coastguard Worker bool strict = false;
193*8fb009dcSAndroid Build Coastguard Worker };
194*8fb009dcSAndroid Build Coastguard Worker
195*8fb009dcSAndroid Build Coastguard Worker // Check reads lines from |source| where each line is in the format of the
196*8fb009dcSAndroid Build Coastguard Worker // coreutils *sum utilities. It attempts to verify each hash by reading the
197*8fb009dcSAndroid Build Coastguard Worker // file named in the line.
198*8fb009dcSAndroid Build Coastguard Worker //
199*8fb009dcSAndroid Build Coastguard Worker // It returns true if all files were verified and, if |args.strict|, no input
200*8fb009dcSAndroid Build Coastguard Worker // lines had formatting errors. Otherwise it prints errors to stderr and
201*8fb009dcSAndroid Build Coastguard Worker // returns false.
Check(const CheckModeArguments & args,const EVP_MD * md,const Source & source)202*8fb009dcSAndroid Build Coastguard Worker static bool Check(const CheckModeArguments &args, const EVP_MD *md,
203*8fb009dcSAndroid Build Coastguard Worker const Source &source) {
204*8fb009dcSAndroid Build Coastguard Worker FILE *file;
205*8fb009dcSAndroid Build Coastguard Worker ScopedFILE scoped_file;
206*8fb009dcSAndroid Build Coastguard Worker
207*8fb009dcSAndroid Build Coastguard Worker if (source.is_stdin()) {
208*8fb009dcSAndroid Build Coastguard Worker file = stdin;
209*8fb009dcSAndroid Build Coastguard Worker } else {
210*8fb009dcSAndroid Build Coastguard Worker ScopedFD fd = OpenFile(source.filename());
211*8fb009dcSAndroid Build Coastguard Worker if (!fd) {
212*8fb009dcSAndroid Build Coastguard Worker return false;
213*8fb009dcSAndroid Build Coastguard Worker }
214*8fb009dcSAndroid Build Coastguard Worker
215*8fb009dcSAndroid Build Coastguard Worker scoped_file = FDToFILE(std::move(fd), "rb");
216*8fb009dcSAndroid Build Coastguard Worker if (!scoped_file) {
217*8fb009dcSAndroid Build Coastguard Worker perror("fdopen");
218*8fb009dcSAndroid Build Coastguard Worker return false;
219*8fb009dcSAndroid Build Coastguard Worker }
220*8fb009dcSAndroid Build Coastguard Worker file = scoped_file.get();
221*8fb009dcSAndroid Build Coastguard Worker }
222*8fb009dcSAndroid Build Coastguard Worker
223*8fb009dcSAndroid Build Coastguard Worker const size_t hex_size = EVP_MD_size(md) * 2;
224*8fb009dcSAndroid Build Coastguard Worker char line[EVP_MAX_MD_SIZE * 2 + 2 /* spaces */ + PATH_MAX + 1 /* newline */ +
225*8fb009dcSAndroid Build Coastguard Worker 1 /* NUL */];
226*8fb009dcSAndroid Build Coastguard Worker unsigned bad_lines = 0;
227*8fb009dcSAndroid Build Coastguard Worker unsigned parsed_lines = 0;
228*8fb009dcSAndroid Build Coastguard Worker unsigned error_lines = 0;
229*8fb009dcSAndroid Build Coastguard Worker unsigned line_no = 0;
230*8fb009dcSAndroid Build Coastguard Worker bool ok = true;
231*8fb009dcSAndroid Build Coastguard Worker bool draining_overlong_line = false;
232*8fb009dcSAndroid Build Coastguard Worker
233*8fb009dcSAndroid Build Coastguard Worker for (;;) {
234*8fb009dcSAndroid Build Coastguard Worker line_no++;
235*8fb009dcSAndroid Build Coastguard Worker
236*8fb009dcSAndroid Build Coastguard Worker if (fgets(line, sizeof(line), file) == nullptr) {
237*8fb009dcSAndroid Build Coastguard Worker if (feof(file)) {
238*8fb009dcSAndroid Build Coastguard Worker break;
239*8fb009dcSAndroid Build Coastguard Worker }
240*8fb009dcSAndroid Build Coastguard Worker fprintf(stderr, "Error reading from input.\n");
241*8fb009dcSAndroid Build Coastguard Worker return false;
242*8fb009dcSAndroid Build Coastguard Worker }
243*8fb009dcSAndroid Build Coastguard Worker
244*8fb009dcSAndroid Build Coastguard Worker size_t len = strlen(line);
245*8fb009dcSAndroid Build Coastguard Worker
246*8fb009dcSAndroid Build Coastguard Worker if (draining_overlong_line) {
247*8fb009dcSAndroid Build Coastguard Worker if (line[len - 1] == '\n') {
248*8fb009dcSAndroid Build Coastguard Worker draining_overlong_line = false;
249*8fb009dcSAndroid Build Coastguard Worker }
250*8fb009dcSAndroid Build Coastguard Worker continue;
251*8fb009dcSAndroid Build Coastguard Worker }
252*8fb009dcSAndroid Build Coastguard Worker
253*8fb009dcSAndroid Build Coastguard Worker const bool overlong = line[len - 1] != '\n' && !feof(file);
254*8fb009dcSAndroid Build Coastguard Worker
255*8fb009dcSAndroid Build Coastguard Worker if (len < hex_size + 2 /* spaces */ + 1 /* filename */ ||
256*8fb009dcSAndroid Build Coastguard Worker line[hex_size] != ' ' ||
257*8fb009dcSAndroid Build Coastguard Worker line[hex_size + 1] != ' ' ||
258*8fb009dcSAndroid Build Coastguard Worker overlong) {
259*8fb009dcSAndroid Build Coastguard Worker bad_lines++;
260*8fb009dcSAndroid Build Coastguard Worker if (args.warn) {
261*8fb009dcSAndroid Build Coastguard Worker fprintf(stderr, "%s: %u: improperly formatted line\n",
262*8fb009dcSAndroid Build Coastguard Worker source.is_stdin() ? kStdinName : source.filename().c_str(), line_no);
263*8fb009dcSAndroid Build Coastguard Worker }
264*8fb009dcSAndroid Build Coastguard Worker if (args.strict) {
265*8fb009dcSAndroid Build Coastguard Worker ok = false;
266*8fb009dcSAndroid Build Coastguard Worker }
267*8fb009dcSAndroid Build Coastguard Worker if (overlong) {
268*8fb009dcSAndroid Build Coastguard Worker draining_overlong_line = true;
269*8fb009dcSAndroid Build Coastguard Worker }
270*8fb009dcSAndroid Build Coastguard Worker continue;
271*8fb009dcSAndroid Build Coastguard Worker }
272*8fb009dcSAndroid Build Coastguard Worker
273*8fb009dcSAndroid Build Coastguard Worker if (line[len - 1] == '\n') {
274*8fb009dcSAndroid Build Coastguard Worker line[len - 1] = 0;
275*8fb009dcSAndroid Build Coastguard Worker len--;
276*8fb009dcSAndroid Build Coastguard Worker }
277*8fb009dcSAndroid Build Coastguard Worker
278*8fb009dcSAndroid Build Coastguard Worker parsed_lines++;
279*8fb009dcSAndroid Build Coastguard Worker
280*8fb009dcSAndroid Build Coastguard Worker // coreutils does not attempt to restrict relative or absolute paths in the
281*8fb009dcSAndroid Build Coastguard Worker // input so nor does this code.
282*8fb009dcSAndroid Build Coastguard Worker std::string calculated_hex_digest;
283*8fb009dcSAndroid Build Coastguard Worker const std::string target_filename(&line[hex_size + 2]);
284*8fb009dcSAndroid Build Coastguard Worker Source target_source;
285*8fb009dcSAndroid Build Coastguard Worker if (target_filename == "-") {
286*8fb009dcSAndroid Build Coastguard Worker // coreutils reads from stdin if the filename is "-".
287*8fb009dcSAndroid Build Coastguard Worker target_source = Source(Source::STDIN);
288*8fb009dcSAndroid Build Coastguard Worker } else {
289*8fb009dcSAndroid Build Coastguard Worker target_source = Source(target_filename);
290*8fb009dcSAndroid Build Coastguard Worker }
291*8fb009dcSAndroid Build Coastguard Worker
292*8fb009dcSAndroid Build Coastguard Worker if (!SumFile(&calculated_hex_digest, md, target_source)) {
293*8fb009dcSAndroid Build Coastguard Worker error_lines++;
294*8fb009dcSAndroid Build Coastguard Worker ok = false;
295*8fb009dcSAndroid Build Coastguard Worker continue;
296*8fb009dcSAndroid Build Coastguard Worker }
297*8fb009dcSAndroid Build Coastguard Worker
298*8fb009dcSAndroid Build Coastguard Worker if (calculated_hex_digest != std::string(line, hex_size)) {
299*8fb009dcSAndroid Build Coastguard Worker if (!args.status) {
300*8fb009dcSAndroid Build Coastguard Worker printf("%s: FAILED\n", target_filename.c_str());
301*8fb009dcSAndroid Build Coastguard Worker }
302*8fb009dcSAndroid Build Coastguard Worker ok = false;
303*8fb009dcSAndroid Build Coastguard Worker continue;
304*8fb009dcSAndroid Build Coastguard Worker }
305*8fb009dcSAndroid Build Coastguard Worker
306*8fb009dcSAndroid Build Coastguard Worker if (!args.quiet) {
307*8fb009dcSAndroid Build Coastguard Worker printf("%s: OK\n", target_filename.c_str());
308*8fb009dcSAndroid Build Coastguard Worker }
309*8fb009dcSAndroid Build Coastguard Worker }
310*8fb009dcSAndroid Build Coastguard Worker
311*8fb009dcSAndroid Build Coastguard Worker if (!args.status) {
312*8fb009dcSAndroid Build Coastguard Worker if (bad_lines > 0 && parsed_lines > 0) {
313*8fb009dcSAndroid Build Coastguard Worker fprintf(stderr, "WARNING: %u line%s improperly formatted\n", bad_lines,
314*8fb009dcSAndroid Build Coastguard Worker bad_lines == 1 ? " is" : "s are");
315*8fb009dcSAndroid Build Coastguard Worker }
316*8fb009dcSAndroid Build Coastguard Worker if (error_lines > 0) {
317*8fb009dcSAndroid Build Coastguard Worker fprintf(stderr, "WARNING: %u computed checksum(s) did NOT match\n",
318*8fb009dcSAndroid Build Coastguard Worker error_lines);
319*8fb009dcSAndroid Build Coastguard Worker }
320*8fb009dcSAndroid Build Coastguard Worker }
321*8fb009dcSAndroid Build Coastguard Worker
322*8fb009dcSAndroid Build Coastguard Worker if (parsed_lines == 0) {
323*8fb009dcSAndroid Build Coastguard Worker fprintf(stderr, "%s: no properly formatted checksum lines found.\n",
324*8fb009dcSAndroid Build Coastguard Worker source.is_stdin() ? kStdinName : source.filename().c_str());
325*8fb009dcSAndroid Build Coastguard Worker ok = false;
326*8fb009dcSAndroid Build Coastguard Worker }
327*8fb009dcSAndroid Build Coastguard Worker
328*8fb009dcSAndroid Build Coastguard Worker return ok;
329*8fb009dcSAndroid Build Coastguard Worker }
330*8fb009dcSAndroid Build Coastguard Worker
331*8fb009dcSAndroid Build Coastguard Worker // DigestSum acts like the coreutils *sum utilites, with the given hash
332*8fb009dcSAndroid Build Coastguard Worker // function.
DigestSum(const EVP_MD * md,const std::vector<std::string> & args)333*8fb009dcSAndroid Build Coastguard Worker static bool DigestSum(const EVP_MD *md,
334*8fb009dcSAndroid Build Coastguard Worker const std::vector<std::string> &args) {
335*8fb009dcSAndroid Build Coastguard Worker bool check_mode = false;
336*8fb009dcSAndroid Build Coastguard Worker CheckModeArguments check_args;
337*8fb009dcSAndroid Build Coastguard Worker bool check_mode_args_given = false;
338*8fb009dcSAndroid Build Coastguard Worker std::vector<Source> sources;
339*8fb009dcSAndroid Build Coastguard Worker
340*8fb009dcSAndroid Build Coastguard Worker auto it = args.begin();
341*8fb009dcSAndroid Build Coastguard Worker while (it != args.end()) {
342*8fb009dcSAndroid Build Coastguard Worker const std::string &arg = *it;
343*8fb009dcSAndroid Build Coastguard Worker if (!arg.empty() && arg[0] != '-') {
344*8fb009dcSAndroid Build Coastguard Worker break;
345*8fb009dcSAndroid Build Coastguard Worker }
346*8fb009dcSAndroid Build Coastguard Worker
347*8fb009dcSAndroid Build Coastguard Worker it++;
348*8fb009dcSAndroid Build Coastguard Worker
349*8fb009dcSAndroid Build Coastguard Worker if (arg == "--") {
350*8fb009dcSAndroid Build Coastguard Worker break;
351*8fb009dcSAndroid Build Coastguard Worker }
352*8fb009dcSAndroid Build Coastguard Worker
353*8fb009dcSAndroid Build Coastguard Worker if (arg == "-") {
354*8fb009dcSAndroid Build Coastguard Worker // "-" ends the argument list and indicates that stdin should be used.
355*8fb009dcSAndroid Build Coastguard Worker sources.push_back(Source(Source::STDIN));
356*8fb009dcSAndroid Build Coastguard Worker break;
357*8fb009dcSAndroid Build Coastguard Worker }
358*8fb009dcSAndroid Build Coastguard Worker
359*8fb009dcSAndroid Build Coastguard Worker if (arg.size() >= 2 && arg[0] == '-' && arg[1] != '-') {
360*8fb009dcSAndroid Build Coastguard Worker for (size_t i = 1; i < arg.size(); i++) {
361*8fb009dcSAndroid Build Coastguard Worker switch (arg[i]) {
362*8fb009dcSAndroid Build Coastguard Worker case 'b':
363*8fb009dcSAndroid Build Coastguard Worker case 't':
364*8fb009dcSAndroid Build Coastguard Worker // Binary/text mode – irrelevent, even on Windows.
365*8fb009dcSAndroid Build Coastguard Worker break;
366*8fb009dcSAndroid Build Coastguard Worker case 'c':
367*8fb009dcSAndroid Build Coastguard Worker check_mode = true;
368*8fb009dcSAndroid Build Coastguard Worker break;
369*8fb009dcSAndroid Build Coastguard Worker case 'w':
370*8fb009dcSAndroid Build Coastguard Worker check_mode_args_given = true;
371*8fb009dcSAndroid Build Coastguard Worker check_args.warn = true;
372*8fb009dcSAndroid Build Coastguard Worker break;
373*8fb009dcSAndroid Build Coastguard Worker default:
374*8fb009dcSAndroid Build Coastguard Worker fprintf(stderr, "Unknown option '%c'.\n", arg[i]);
375*8fb009dcSAndroid Build Coastguard Worker return false;
376*8fb009dcSAndroid Build Coastguard Worker }
377*8fb009dcSAndroid Build Coastguard Worker }
378*8fb009dcSAndroid Build Coastguard Worker } else if (arg == "--binary" || arg == "--text") {
379*8fb009dcSAndroid Build Coastguard Worker // Binary/text mode – irrelevent, even on Windows.
380*8fb009dcSAndroid Build Coastguard Worker } else if (arg == "--check") {
381*8fb009dcSAndroid Build Coastguard Worker check_mode = true;
382*8fb009dcSAndroid Build Coastguard Worker } else if (arg == "--quiet") {
383*8fb009dcSAndroid Build Coastguard Worker check_mode_args_given = true;
384*8fb009dcSAndroid Build Coastguard Worker check_args.quiet = true;
385*8fb009dcSAndroid Build Coastguard Worker } else if (arg == "--status") {
386*8fb009dcSAndroid Build Coastguard Worker check_mode_args_given = true;
387*8fb009dcSAndroid Build Coastguard Worker check_args.status = true;
388*8fb009dcSAndroid Build Coastguard Worker } else if (arg == "--warn") {
389*8fb009dcSAndroid Build Coastguard Worker check_mode_args_given = true;
390*8fb009dcSAndroid Build Coastguard Worker check_args.warn = true;
391*8fb009dcSAndroid Build Coastguard Worker } else if (arg == "--strict") {
392*8fb009dcSAndroid Build Coastguard Worker check_mode_args_given = true;
393*8fb009dcSAndroid Build Coastguard Worker check_args.strict = true;
394*8fb009dcSAndroid Build Coastguard Worker } else {
395*8fb009dcSAndroid Build Coastguard Worker fprintf(stderr, "Unknown option '%s'.\n", arg.c_str());
396*8fb009dcSAndroid Build Coastguard Worker return false;
397*8fb009dcSAndroid Build Coastguard Worker }
398*8fb009dcSAndroid Build Coastguard Worker }
399*8fb009dcSAndroid Build Coastguard Worker
400*8fb009dcSAndroid Build Coastguard Worker if (check_mode_args_given && !check_mode) {
401*8fb009dcSAndroid Build Coastguard Worker fprintf(
402*8fb009dcSAndroid Build Coastguard Worker stderr,
403*8fb009dcSAndroid Build Coastguard Worker "Check mode arguments are only meaningful when verifying checksums.\n");
404*8fb009dcSAndroid Build Coastguard Worker return false;
405*8fb009dcSAndroid Build Coastguard Worker }
406*8fb009dcSAndroid Build Coastguard Worker
407*8fb009dcSAndroid Build Coastguard Worker for (; it != args.end(); it++) {
408*8fb009dcSAndroid Build Coastguard Worker sources.push_back(Source(*it));
409*8fb009dcSAndroid Build Coastguard Worker }
410*8fb009dcSAndroid Build Coastguard Worker
411*8fb009dcSAndroid Build Coastguard Worker if (sources.empty()) {
412*8fb009dcSAndroid Build Coastguard Worker sources.push_back(Source(Source::STDIN));
413*8fb009dcSAndroid Build Coastguard Worker }
414*8fb009dcSAndroid Build Coastguard Worker
415*8fb009dcSAndroid Build Coastguard Worker bool ok = true;
416*8fb009dcSAndroid Build Coastguard Worker
417*8fb009dcSAndroid Build Coastguard Worker if (check_mode) {
418*8fb009dcSAndroid Build Coastguard Worker for (auto &source : sources) {
419*8fb009dcSAndroid Build Coastguard Worker ok &= Check(check_args, md, source);
420*8fb009dcSAndroid Build Coastguard Worker }
421*8fb009dcSAndroid Build Coastguard Worker } else {
422*8fb009dcSAndroid Build Coastguard Worker for (auto &source : sources) {
423*8fb009dcSAndroid Build Coastguard Worker ok &= PrintFileSum(md, source);
424*8fb009dcSAndroid Build Coastguard Worker }
425*8fb009dcSAndroid Build Coastguard Worker }
426*8fb009dcSAndroid Build Coastguard Worker
427*8fb009dcSAndroid Build Coastguard Worker return ok;
428*8fb009dcSAndroid Build Coastguard Worker }
429*8fb009dcSAndroid Build Coastguard Worker
MD5Sum(const std::vector<std::string> & args)430*8fb009dcSAndroid Build Coastguard Worker bool MD5Sum(const std::vector<std::string> &args) {
431*8fb009dcSAndroid Build Coastguard Worker return DigestSum(EVP_md5(), args);
432*8fb009dcSAndroid Build Coastguard Worker }
433*8fb009dcSAndroid Build Coastguard Worker
SHA1Sum(const std::vector<std::string> & args)434*8fb009dcSAndroid Build Coastguard Worker bool SHA1Sum(const std::vector<std::string> &args) {
435*8fb009dcSAndroid Build Coastguard Worker return DigestSum(EVP_sha1(), args);
436*8fb009dcSAndroid Build Coastguard Worker }
437*8fb009dcSAndroid Build Coastguard Worker
SHA224Sum(const std::vector<std::string> & args)438*8fb009dcSAndroid Build Coastguard Worker bool SHA224Sum(const std::vector<std::string> &args) {
439*8fb009dcSAndroid Build Coastguard Worker return DigestSum(EVP_sha224(), args);
440*8fb009dcSAndroid Build Coastguard Worker }
441*8fb009dcSAndroid Build Coastguard Worker
SHA256Sum(const std::vector<std::string> & args)442*8fb009dcSAndroid Build Coastguard Worker bool SHA256Sum(const std::vector<std::string> &args) {
443*8fb009dcSAndroid Build Coastguard Worker return DigestSum(EVP_sha256(), args);
444*8fb009dcSAndroid Build Coastguard Worker }
445*8fb009dcSAndroid Build Coastguard Worker
SHA384Sum(const std::vector<std::string> & args)446*8fb009dcSAndroid Build Coastguard Worker bool SHA384Sum(const std::vector<std::string> &args) {
447*8fb009dcSAndroid Build Coastguard Worker return DigestSum(EVP_sha384(), args);
448*8fb009dcSAndroid Build Coastguard Worker }
449*8fb009dcSAndroid Build Coastguard Worker
SHA512Sum(const std::vector<std::string> & args)450*8fb009dcSAndroid Build Coastguard Worker bool SHA512Sum(const std::vector<std::string> &args) {
451*8fb009dcSAndroid Build Coastguard Worker return DigestSum(EVP_sha512(), args);
452*8fb009dcSAndroid Build Coastguard Worker }
453*8fb009dcSAndroid Build Coastguard Worker
SHA512256Sum(const std::vector<std::string> & args)454*8fb009dcSAndroid Build Coastguard Worker bool SHA512256Sum(const std::vector<std::string> &args) {
455*8fb009dcSAndroid Build Coastguard Worker return DigestSum(EVP_sha512_256(), args);
456*8fb009dcSAndroid Build Coastguard Worker }
457