1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // Md5sum implementation for Android. This version handles files as well as 6 // directories. Its output is sorted by file path. 7 8 #include <fstream> 9 #include <iostream> 10 #include <set> 11 #include <string> 12 13 #include "base/file_util.h" 14 #include "base/files/file_enumerator.h" 15 #include "base/files/file_path.h" 16 #include "base/logging.h" 17 #include "base/md5.h" 18 19 namespace { 20 21 const int kBufferSize = 1024; 22 23 // Returns whether |path|'s MD5 was successfully written to |digest_string|. 24 bool MD5Sum(const char* path, std::string* digest_string) { 25 std::ifstream stream(path); 26 if (!stream.good()) { 27 LOG(ERROR) << "Could not open file " << path; 28 return false; 29 } 30 base::MD5Context ctx; 31 base::MD5Init(&ctx); 32 char buf[kBufferSize]; 33 while (stream.good()) { 34 std::streamsize bytes_read = stream.readsome(buf, sizeof(buf)); 35 if (bytes_read == 0) 36 break; 37 base::MD5Update(&ctx, base::StringPiece(buf, bytes_read)); 38 } 39 if (stream.fail()) { 40 LOG(ERROR) << "Error reading file " << path; 41 return false; 42 } 43 base::MD5Digest digest; 44 base::MD5Final(&digest, &ctx); 45 *digest_string = base::MD5DigestToBase16(digest); 46 return true; 47 } 48 49 // Returns the set of all files contained in |files|. This handles directories 50 // by walking them recursively. Excludes, .svn directories and file under them. 51 std::set<std::string> MakeFileSet(const char** files) { 52 const std::string svn_dir_component = FILE_PATH_LITERAL("/.svn/"); 53 std::set<std::string> file_set; 54 for (const char** file = files; *file; ++file) { 55 base::FilePath file_path(*file); 56 if (base::DirectoryExists(file_path)) { 57 base::FileEnumerator file_enumerator( 58 file_path, true /* recurse */, base::FileEnumerator::FILES); 59 for (base::FilePath child, empty; 60 (child = file_enumerator.Next()) != empty; ) { 61 // If the path contains /.svn/, ignore it. 62 if (child.value().find(svn_dir_component) == std::string::npos) { 63 child = base::MakeAbsoluteFilePath(child); 64 file_set.insert(child.value()); 65 } 66 } 67 } else { 68 file_set.insert(*file); 69 } 70 } 71 return file_set; 72 } 73 74 } // namespace 75 76 int main(int argc, const char* argv[]) { 77 if (argc < 2) { 78 LOG(ERROR) << "Usage: md5sum <path/to/file_or_dir>..."; 79 return 1; 80 } 81 const std::set<std::string> files = MakeFileSet(argv + 1); 82 bool failed = false; 83 std::string digest; 84 for (std::set<std::string>::const_iterator it = files.begin(); 85 it != files.end(); ++it) { 86 if (!MD5Sum(it->c_str(), &digest)) 87 failed = true; 88 base::FilePath file_path(*it); 89 std::cout << digest << " " 90 << base::MakeAbsoluteFilePath(file_path).value() << std::endl; 91 } 92 return failed; 93 } 94