123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148 |
- // Copyright (c) 2012 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- // Md5sum implementation for Android. In gzip mode, takes in a list of files,
- // and outputs a list of Md5sums in the same order. Otherwise,
- #include <stddef.h>
- #include <dirent.h>
- #include <fstream>
- #include <iostream>
- #include <memory>
- #include <set>
- #include <string>
- #include "base/base64.h"
- #include "base/hash/md5.h"
- #include "third_party/zlib/google/compression_utils_portable.h"
- namespace {
- // Only used in the gzip mode.
- const char kFilePathDelimiter = ';';
- const int kMD5HashLength = 16;
- // Returns whether |path|'s MD5 was successfully written to |digest_string|.
- bool MD5Sum(const std::string& path, std::string* digest_string) {
- FILE* fd = fopen(path.c_str(), "rb");
- if (!fd) {
- std::cerr << "Could not open file " << path << std::endl;
- return false;
- }
- base::MD5Context ctx;
- base::MD5Init(&ctx);
- const size_t kBufferSize = 1 << 16;
- std::unique_ptr<char[]> buf(new char[kBufferSize]);
- size_t len;
- while ((len = fread(buf.get(), 1, kBufferSize, fd)) > 0)
- base::MD5Update(&ctx, base::StringPiece(buf.get(), len));
- if (ferror(fd)) {
- std::cerr << "Error reading file " << path << std::endl;
- return false;
- }
- fclose(fd);
- base::MD5Digest digest;
- base::MD5Final(&digest, &ctx);
- *digest_string = base::MD5DigestToBase16(digest);
- return true;
- }
- void MakeFileSetHelper(const std::string& path,
- std::set<std::string>& file_set) {
- DIR* dir = opendir(path.c_str());
- if (!dir) {
- file_set.insert(path);
- return;
- }
- dirent* entry;
- while ((entry = readdir(dir))) {
- if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
- continue;
- MakeFileSetHelper(path + '/' + entry->d_name, file_set);
- }
- closedir(dir);
- }
- // Returns the set of all files contained in |files|. This handles directories
- // by walking them recursively. Excludes, .svn directories and file under them.
- std::vector<std::string> MakeFileSet(const char** files) {
- std::set<std::string> file_set;
- for (const char** file = files; *file; ++file) {
- MakeFileSetHelper(*file, file_set);
- }
- return std::vector<std::string>(file_set.begin(), file_set.end());
- }
- std::vector<std::string> StringSplit(const std::string& str, char delim) {
- std::vector<std::string> ret;
- size_t found_idx = str.find(delim);
- size_t start_idx = 0;
- while (found_idx != std::string::npos) {
- ret.push_back(str.substr(start_idx, found_idx - start_idx));
- start_idx = found_idx + 1;
- found_idx = str.find(delim, start_idx);
- }
- ret.push_back(str.substr(start_idx, std::string::npos));
- return ret;
- }
- std::vector<std::string> MakeFileListFromCompressedList(const char* data) {
- std::string gzipdata;
- // Expected compressed input is using Base64 encoding, we got convert it
- // to a regular string before passing it to zlib.
- base::Base64Decode(base::StringPiece(data), &gzipdata);
- size_t compressed_size = gzipdata.size();
- unsigned long decompressed_size = zlib_internal::GetGzipUncompressedSize(
- reinterpret_cast<const Bytef*>(gzipdata.c_str()), compressed_size);
- std::string decompressed(decompressed_size, '#');
- // We can skip an extraneous copy by relying on a C++11 std::string guarantee
- // of contiguous memory access to a string.
- zlib_internal::UncompressHelper(
- zlib_internal::WrapperType::GZIP,
- reinterpret_cast<unsigned char*>(&decompressed[0]), &decompressed_size,
- reinterpret_cast<const unsigned char*>(gzipdata.c_str()),
- compressed_size);
- return StringSplit(decompressed, kFilePathDelimiter);
- }
- } // namespace
- int main(int argc, const char* argv[]) {
- bool gzip_mode = argc >= 2 && strcmp("-gz", argv[1]) == 0;
- if (argc < 2 || (gzip_mode && argc < 3)) {
- std::cerr << "Usage: md5sum <path/to/file_or_dir>... or md5sum "
- << "-gz base64-gzipped-'" << kFilePathDelimiter
- << "'-separated-files" << std::endl;
- return 1;
- }
- std::vector<std::string> files;
- if (gzip_mode) {
- files = MakeFileListFromCompressedList(argv[2]);
- } else {
- files = MakeFileSet(argv + 1);
- }
- bool failed = false;
- std::string digest;
- for (const auto& file : files) {
- if (!MD5Sum(file, &digest)) {
- failed = true;
- continue;
- }
- if (gzip_mode) {
- std::cout << digest.substr(0, kMD5HashLength) << std::endl;
- } else {
- std::cout << digest << " " << file << std::endl;
- }
- }
- return failed;
- }
|