1 //===-- FileSystem.cpp ------------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "lldb/Host/FileSystem.h"
11 
12 #include "llvm/Support/MD5.h"
13 
14 #include <algorithm>
15 #include <fstream>
16 #include <vector>
17 
18 using namespace lldb;
19 using namespace lldb_private;
20 
21 namespace {
22 
23 bool
24 CalcMD5(const FileSpec &file_spec, uint64_t offset, uint64_t length, llvm::MD5::MD5Result &md5_result)
25 {
26     llvm::MD5 md5_hash;
27     std::ifstream file(file_spec.GetPath(), std::ios::binary);
28     if (!file.is_open())
29         return false;
30 
31     if (offset > 0)
32         file.seekg(offset, file.beg);
33 
34     std::vector<char> read_buf(4096);
35     uint64_t total_read_bytes = 0;
36     while (!file.eof())
37     {
38         const uint64_t to_read = (length > 0) ?
39             std::min(static_cast<uint64_t>(read_buf.size()), length - total_read_bytes) :
40             read_buf.size();
41         if (to_read == 0)
42             break;
43 
44         file.read(&read_buf[0], to_read);
45         const auto read_bytes = file.gcount();
46         if (read_bytes == 0)
47             break;
48 
49         md5_hash.update(llvm::StringRef(&read_buf[0], read_bytes));
50         total_read_bytes += read_bytes;
51     }
52 
53     md5_hash.final(md5_result);
54     return true;
55 }
56 
57 }  // namespace
58 
59 bool
60 FileSystem::CalculateMD5(const FileSpec &file_spec, uint64_t &low, uint64_t &high)
61 {
62     return CalculateMD5(file_spec, 0, 0, low, high);
63 }
64 
65 bool
66 FileSystem::CalculateMD5(const FileSpec &file_spec,
67                          uint64_t offset,
68                          uint64_t length,
69                          uint64_t &low,
70                          uint64_t &high)
71 {
72     llvm::MD5::MD5Result md5_result;
73     if (!CalcMD5(file_spec, offset, length, md5_result))
74         return false;
75 
76     const auto uint64_res = reinterpret_cast<const uint64_t*>(md5_result);
77     high = uint64_res[0];
78     low = uint64_res[1];
79 
80     return true;
81 }
82 
83 bool
84 FileSystem::CalculateMD5AsString(const FileSpec &file_spec, std::string& digest_str)
85 {
86     return CalculateMD5AsString(file_spec, 0, 0, digest_str);
87 }
88 
89 bool
90 FileSystem::CalculateMD5AsString(const FileSpec &file_spec,
91                                  uint64_t offset,
92                                  uint64_t length,
93                                  std::string& digest_str)
94 {
95     llvm::MD5::MD5Result md5_result;
96     if (!CalcMD5(file_spec, offset, length, md5_result))
97         return false;
98 
99     llvm::SmallString<32> result_str;
100     llvm::MD5::stringifyResult(md5_result, result_str);
101     digest_str = result_str.c_str();
102     return true;
103 }
104