11c3bbb01SEd Maste //===-- FileSystem.cpp ------------------------------------------*- C++ -*-===//
21c3bbb01SEd Maste //
31c3bbb01SEd Maste //                     The LLVM Compiler Infrastructure
41c3bbb01SEd Maste //
51c3bbb01SEd Maste // This file is distributed under the University of Illinois Open Source
61c3bbb01SEd Maste // License. See LICENSE.TXT for details.
71c3bbb01SEd Maste //
81c3bbb01SEd Maste //===----------------------------------------------------------------------===//
91c3bbb01SEd Maste 
101c3bbb01SEd Maste #include "lldb/Host/FileSystem.h"
111c3bbb01SEd Maste 
12435933ddSDimitry Andric #include "llvm/Support/FileSystem.h"
131c3bbb01SEd Maste #include "llvm/Support/MD5.h"
141c3bbb01SEd Maste 
151c3bbb01SEd Maste #include <algorithm>
161c3bbb01SEd Maste #include <fstream>
171c3bbb01SEd Maste #include <vector>
181c3bbb01SEd Maste 
191c3bbb01SEd Maste using namespace lldb;
201c3bbb01SEd Maste using namespace lldb_private;
211c3bbb01SEd Maste 
221c3bbb01SEd Maste namespace {
231c3bbb01SEd Maste 
24435933ddSDimitry Andric bool CalcMD5(const FileSpec &file_spec, uint64_t offset, uint64_t length,
25435933ddSDimitry Andric              llvm::MD5::MD5Result &md5_result) {
261c3bbb01SEd Maste   llvm::MD5 md5_hash;
271c3bbb01SEd Maste   std::ifstream file(file_spec.GetPath(), std::ios::binary);
281c3bbb01SEd Maste   if (!file.is_open())
291c3bbb01SEd Maste     return false;
301c3bbb01SEd Maste 
311c3bbb01SEd Maste   if (offset > 0)
321c3bbb01SEd Maste     file.seekg(offset, file.beg);
331c3bbb01SEd Maste 
341c3bbb01SEd Maste   std::vector<char> read_buf(4096);
351c3bbb01SEd Maste   uint64_t total_read_bytes = 0;
36435933ddSDimitry Andric   while (!file.eof()) {
37435933ddSDimitry Andric     const uint64_t to_read =
38435933ddSDimitry Andric         (length > 0) ? std::min(static_cast<uint64_t>(read_buf.size()),
39435933ddSDimitry Andric                                 length - total_read_bytes)
40435933ddSDimitry Andric                      : read_buf.size();
411c3bbb01SEd Maste     if (to_read == 0)
421c3bbb01SEd Maste       break;
431c3bbb01SEd Maste 
441c3bbb01SEd Maste     file.read(&read_buf[0], to_read);
451c3bbb01SEd Maste     const auto read_bytes = file.gcount();
461c3bbb01SEd Maste     if (read_bytes == 0)
471c3bbb01SEd Maste       break;
481c3bbb01SEd Maste 
491c3bbb01SEd Maste     md5_hash.update(llvm::StringRef(&read_buf[0], read_bytes));
501c3bbb01SEd Maste     total_read_bytes += read_bytes;
511c3bbb01SEd Maste   }
521c3bbb01SEd Maste 
531c3bbb01SEd Maste   md5_hash.final(md5_result);
541c3bbb01SEd Maste   return true;
551c3bbb01SEd Maste }
561c3bbb01SEd Maste 
571c3bbb01SEd Maste } // namespace
581c3bbb01SEd Maste 
59435933ddSDimitry Andric bool FileSystem::CalculateMD5(const FileSpec &file_spec, uint64_t &low,
60435933ddSDimitry Andric                               uint64_t &high) {
611c3bbb01SEd Maste   return CalculateMD5(file_spec, 0, 0, low, high);
621c3bbb01SEd Maste }
631c3bbb01SEd Maste 
64435933ddSDimitry Andric bool FileSystem::CalculateMD5(const FileSpec &file_spec, uint64_t offset,
65435933ddSDimitry Andric                               uint64_t length, uint64_t &low, uint64_t &high) {
661c3bbb01SEd Maste   llvm::MD5::MD5Result md5_result;
671c3bbb01SEd Maste   if (!CalcMD5(file_spec, offset, length, md5_result))
681c3bbb01SEd Maste     return false;
691c3bbb01SEd Maste 
701c3bbb01SEd Maste   const auto uint64_res = reinterpret_cast<const uint64_t *>(md5_result);
711c3bbb01SEd Maste   high = uint64_res[0];
721c3bbb01SEd Maste   low = uint64_res[1];
731c3bbb01SEd Maste 
741c3bbb01SEd Maste   return true;
751c3bbb01SEd Maste }
761c3bbb01SEd Maste 
77435933ddSDimitry Andric bool FileSystem::CalculateMD5AsString(const FileSpec &file_spec,
78435933ddSDimitry Andric                                       std::string &digest_str) {
791c3bbb01SEd Maste   return CalculateMD5AsString(file_spec, 0, 0, digest_str);
801c3bbb01SEd Maste }
811c3bbb01SEd Maste 
82435933ddSDimitry Andric bool FileSystem::CalculateMD5AsString(const FileSpec &file_spec,
83435933ddSDimitry Andric                                       uint64_t offset, uint64_t length,
84435933ddSDimitry Andric                                       std::string &digest_str) {
851c3bbb01SEd Maste   llvm::MD5::MD5Result md5_result;
861c3bbb01SEd Maste   if (!CalcMD5(file_spec, offset, length, md5_result))
871c3bbb01SEd Maste     return false;
881c3bbb01SEd Maste 
891c3bbb01SEd Maste   llvm::SmallString<32> result_str;
901c3bbb01SEd Maste   llvm::MD5::stringifyResult(md5_result, result_str);
911c3bbb01SEd Maste   digest_str = result_str.c_str();
921c3bbb01SEd Maste   return true;
931c3bbb01SEd Maste }
94435933ddSDimitry Andric 
95435933ddSDimitry Andric llvm::sys::TimePoint<>
96435933ddSDimitry Andric FileSystem::GetModificationTime(const FileSpec &file_spec) {
97435933ddSDimitry Andric   llvm::sys::fs::file_status status;
98435933ddSDimitry Andric   std::error_code ec = llvm::sys::fs::status(file_spec.GetPath(), status);
99435933ddSDimitry Andric   if (ec)
100435933ddSDimitry Andric     return llvm::sys::TimePoint<>();
101435933ddSDimitry Andric   return status.getLastModificationTime();
102435933ddSDimitry Andric }
103