131 lines
2.3 KiB
C++
131 lines
2.3 KiB
C++
#include "hash.h"
|
|
|
|
#include <cstring>
|
|
#include <fcntl.h>
|
|
#include <iomanip>
|
|
#include <sstream>
|
|
#include <sys/mman.h>
|
|
#include <unistd.h>
|
|
|
|
#include <openssl/sha.h>
|
|
|
|
#include <Log.h>
|
|
|
|
const static size_t HASHSIZE = 32; // the size of the SHA256 Hashsum in bytes
|
|
|
|
Hash::Hash() {}
|
|
|
|
Hash::Hash(const Hash& h) : data(new unsigned char[HASHSIZE]) {
|
|
std::memcpy(data, h.data, HASHSIZE);
|
|
}
|
|
|
|
Hash::Hash(Hash&& h) : data(h.data) {
|
|
h.data = nullptr;
|
|
}
|
|
|
|
Hash::~Hash() {
|
|
if(data) {
|
|
delete[] data;
|
|
data = nullptr;
|
|
}
|
|
}
|
|
|
|
|
|
bool Hash::create(Hash& h, const std::string& file) {
|
|
int fd = ::open(file.c_str(), O_RDONLY);
|
|
|
|
bool result = Hash::create(h, fd);
|
|
|
|
::close(fd);
|
|
|
|
return result;
|
|
}
|
|
|
|
bool Hash::create(Hash& h, int fd) {
|
|
if(fd < 0 || h.data) {
|
|
return false;
|
|
}
|
|
|
|
SHA256_CTX hashctx;
|
|
if(SHA256_Init(&hashctx) != 1) {
|
|
Log::error << "Can not create SHA256 CTX";
|
|
return false;
|
|
}
|
|
|
|
//determine filesize
|
|
loff_t fs = lseek64(fd, 0, SEEK_END);
|
|
lseek64(fd, 0, SEEK_SET);
|
|
|
|
void* mapping = ::mmap(NULL, fs, PROT_READ, MAP_SHARED | MAP_POPULATE, fd, 0);
|
|
if(mapping == MAP_FAILED) {
|
|
return false;
|
|
}
|
|
|
|
::madvise(mapping, fs, MADV_DONTDUMP);
|
|
::madvise(mapping, fs, MADV_DONTFORK);
|
|
::madvise(mapping, fs, MADV_SEQUENTIAL);
|
|
::madvise(mapping, fs, MADV_WILLNEED);
|
|
|
|
if(SHA256_Update(&hashctx, mapping, fs) != 1) {
|
|
Log::error << "Can not update hash";
|
|
return false;
|
|
}
|
|
|
|
::munmap(mapping, fs);
|
|
|
|
unsigned char* md = new unsigned char[HASHSIZE];
|
|
if(SHA256_Final(md, &hashctx) != 1) {
|
|
Log::error << "Can not finalize hash";
|
|
return false;
|
|
}
|
|
|
|
h.data = md;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
Hash::operator bool() const {
|
|
return data;
|
|
}
|
|
|
|
Hash::operator std::string() const {
|
|
std::stringstream str;
|
|
str << *this;
|
|
return str.str();
|
|
}
|
|
|
|
|
|
bool Hash::operator==(const Hash& rhs) const {
|
|
// same data ptr
|
|
if(data == rhs.data) return true;
|
|
|
|
// both no data
|
|
if(static_cast<bool>(data) == static_cast<bool>(rhs) && data == nullptr) return true;
|
|
|
|
return std::memcmp(data, rhs.data, HASHSIZE) == 0;
|
|
}
|
|
|
|
bool Hash::operator!=(const Hash& rhs) const {
|
|
return !(*this == rhs);
|
|
}
|
|
|
|
|
|
std::ostream& operator<<(std::ostream& str, const Hash& rhs) {
|
|
if(!rhs.data) {
|
|
return str << "[empty hash]";
|
|
}
|
|
|
|
std::ios_base::fmtflags flags = str.flags();
|
|
|
|
str << std::hex << std::setfill('0');
|
|
|
|
for(size_t i = 0; i < HASHSIZE; ++i) {
|
|
str << std::setw(2) << (int) rhs.data[i];
|
|
}
|
|
|
|
str.setf(flags);
|
|
|
|
return str;
|
|
}
|