From ed219c1af1303b445f2a9e61caae78664e33f845 Mon Sep 17 00:00:00 2001 From: Slava Monich Date: Tue, 30 Jan 2018 00:26:06 +0200 Subject: [PATCH] [app] Moved hashing utilities to BooksUtil --- app/src/BooksImportModel.cpp | 64 ++---------------------- app/src/BooksUtil.cpp | 94 ++++++++++++++++++++++++++++++++++-- app/src/BooksUtil.h | 12 +++-- 3 files changed, 104 insertions(+), 66 deletions(-) diff --git a/app/src/BooksImportModel.cpp b/app/src/BooksImportModel.cpp index 061d174..bd6a7f0 100644 --- a/app/src/BooksImportModel.cpp +++ b/app/src/BooksImportModel.cpp @@ -35,20 +35,10 @@ #include "BooksStorage.h" #include "BooksTask.h" #include "BooksUtil.h" -#include "BooksDefs.h" #include "HarbourDebug.h" #include -#include - -#include -#include -#include - -#define DIGEST_XATTR XATTR_USER_PREFIX BOOKS_APP_NAME ".md5-hash" -#define DIGEST_TYPE (QCryptographicHash::Md5) -#define DIGEST_SIZE (16) enum BooksImportRole { BooksImportRoleTitle = Qt::UserRole, @@ -103,7 +93,6 @@ public: void performTask(); void scanDir(QDir aDir); bool isDuplicate(QString aPath, QFileInfoList aFileList); - QByteArray calculateFileHash(QString aPath); QByteArray getFileHash(QString aPath); Q_SIGNALS: @@ -134,60 +123,16 @@ BooksImportModel::Task::~Task() delete [] iBuf; } -QByteArray BooksImportModel::Task::calculateFileHash(QString aPath) -{ - QByteArray result; - QFile file(aPath); - if (file.open(QIODevice::ReadOnly)) { - const qint64 size = file.size(); - uchar* map = file.map(0, size); - if (map) { - const char* ptr = (char*)map; - qint64 bytesLeft = size; - QCryptographicHash hash(DIGEST_TYPE); - hash.reset(); - while (!isCanceled() && bytesLeft > DIGEST_SIZE) { - hash.addData(ptr, DIGEST_SIZE); - bytesLeft -= DIGEST_SIZE; - ptr += DIGEST_SIZE; - } - if (!isCanceled()) { - if (bytesLeft) { - hash.addData(ptr, bytesLeft); - } - result = hash.result(); - HASSERT(result.size() == DIGEST_SIZE); - HDEBUG(qPrintable(aPath) << QString(result.toHex())); - } - file.unmap(map); - } else { - HWARN("error mapping" << qPrintable(aPath)); - } - file.close(); - } - return result; -} - QByteArray BooksImportModel::Task::getFileHash(QString aPath) { if (iFileHash.contains(aPath)) { return iFileHash.value(aPath); } else { - QByteArray hash; - char attr[DIGEST_SIZE]; - QByteArray fname = aPath.toLocal8Bit(); - if (getxattr(fname, DIGEST_XATTR, attr, sizeof(attr)) == DIGEST_SIZE) { - hash = QByteArray(attr, sizeof(attr)); - HDEBUG(qPrintable(aPath) << QString(hash.toHex())); - } else { - hash = calculateFileHash(aPath); - if (hash.size() == DIGEST_SIZE && - setxattr(fname, DIGEST_XATTR, hash, hash.size(), 0)) { - HDEBUG("Failed to set " DIGEST_XATTR " xattr on" << - fname.constData() << ":" << strerror(errno)); - } + QByteArray hash(BooksUtil::fileHashAttr(aPath)); + if (hash.isEmpty()) { + hash = BooksUtil::computeFileHashAndSetAttr(aPath, this); } - if (hash.size() == DIGEST_SIZE) { + if (!hash.isEmpty()) { iFileHash.insert(aPath, hash); iHashFile.insert(hash, aPath); } @@ -249,7 +194,6 @@ void BooksImportModel::Task::scanDir(QDir aDir) if (!isDuplicate(filePath, iDestFiles) && !isDuplicate(filePath, iSrcFiles)) { BooksBook* newBook = new BooksBook(dummy, QString(), book); - newBook->moveToThread(thread()); iBooks.append(newBook); iSrcFiles.append(fileInfo); HDEBUG("found" << path.c_str() << newBook->title()); diff --git a/app/src/BooksUtil.cpp b/app/src/BooksUtil.cpp index d20723d..70e21b9 100644 --- a/app/src/BooksUtil.cpp +++ b/app/src/BooksUtil.cpp @@ -1,6 +1,6 @@ /* - * Copyright (C) 2015 Jolla Ltd. - * Contact: Slava Monich + * Copyright (C) 2015-2018 Jolla Ltd. + * Copyright (C) 2015-2018 Slava Monich * * You may use this file under the terms of the BSD license as follows: * @@ -14,7 +14,7 @@ * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. - * * Neither the name of Nemo Mobile nor the names of its contributors + * * Neither the name of Jolla Ltd nor the names of its contributors * may be used to endorse or promote products derived from this * software without specific prior written permission. * @@ -32,6 +32,8 @@ */ #include "BooksUtil.h" +#include "BooksDefs.h" +#include "BooksTask.h" #include "HarbourDebug.h" #include "ZLDir.h" @@ -39,6 +41,16 @@ #include +#include + +#include +#include +#include + +#define DIGEST_XATTR XATTR_USER_PREFIX BOOKS_APP_NAME ".md5-hash" +#define DIGEST_TYPE (QCryptographicHash::Md5) +#define DIGEST_SIZE (16) + shared_ptr BooksUtil::bookFromFile(std::string aPath) { shared_ptr book; @@ -78,6 +90,82 @@ shared_ptr BooksUtil::bookFromFile(std::string aPath) return book; } +QByteArray BooksUtil::computeFileHash(QString aPath, BooksTask* aTask) +{ + QByteArray result; + QFile file(aPath); + if (file.open(QIODevice::ReadOnly)) { + const qint64 size = file.size(); + uchar* map = file.map(0, size); + if (map) { + const char* ptr = (char*)map; + qint64 bytesLeft = size; + QCryptographicHash hash(DIGEST_TYPE); + hash.reset(); + if (aTask) { + while (!aTask->isCanceled() && bytesLeft > DIGEST_SIZE) { + hash.addData(ptr, DIGEST_SIZE); + bytesLeft -= DIGEST_SIZE; + ptr += DIGEST_SIZE; + } + } else { + while (bytesLeft > DIGEST_SIZE) { + hash.addData(ptr, DIGEST_SIZE); + bytesLeft -= DIGEST_SIZE; + ptr += DIGEST_SIZE; + } + } + if (!aTask || !aTask->isCanceled()) { + if (bytesLeft) { + hash.addData(ptr, bytesLeft); + } + result = hash.result(); + HASSERT(result.size() == DIGEST_SIZE); + HDEBUG(qPrintable(aPath) << QString(result.toHex())); + } + file.unmap(map); + } else { + HWARN("error mapping" << qPrintable(aPath)); + } + file.close(); + } + return result; +} + +QByteArray BooksUtil::fileHashAttr(QString aPath) +{ + QByteArray hash; + QByteArray fname(aPath.toLocal8Bit()); + char attr[DIGEST_SIZE]; + if (getxattr(fname, DIGEST_XATTR, attr, sizeof(attr)) == DIGEST_SIZE) { + hash = QByteArray(attr, sizeof(attr)); + HDEBUG(qPrintable(aPath) << QString(hash.toHex())); + } + return hash; +} + +bool BooksUtil::setFileHashAttr(QString aPath, QByteArray aHash) +{ + if (aHash.size() == DIGEST_SIZE) { + QByteArray fname(aPath.toLocal8Bit()); + if (setxattr(fname, DIGEST_XATTR, aHash, aHash.size(), 0) == 0) { + return true; + } + HDEBUG("Failed to set " DIGEST_XATTR " xattr on" << + fname.constData() << ":" << strerror(errno)); + } + return false; +} + +QByteArray BooksUtil::computeFileHashAndSetAttr(QString aPath, BooksTask* aTask) +{ + QByteArray hash = computeFileHash(aPath, aTask); + if (!hash.isEmpty()) { + BooksUtil::setFileHashAttr(aPath, hash); + } + return hash; +} + bool BooksUtil::isValidFileName(QString aName) { return !aName.isEmpty() && diff --git a/app/src/BooksUtil.h b/app/src/BooksUtil.h index 9fa801b..506e844 100644 --- a/app/src/BooksUtil.h +++ b/app/src/BooksUtil.h @@ -1,6 +1,6 @@ /* - * Copyright (C) 2015 Jolla Ltd. - * Contact: Slava Monich + * Copyright (C) 2015-2018 Jolla Ltd. + * Copyright (C) 2015-2018 Slava Monich * * You may use this file under the terms of the BSD license as follows: * @@ -14,7 +14,7 @@ * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. - * * Neither the name of Nemo Mobile nor the names of its contributors + * * Neither the name of Jolla Ltd nor the names of its contributors * may be used to endorse or promote products derived from this * software without specific prior written permission. * @@ -40,10 +40,16 @@ #include +class BooksTask; + namespace BooksUtil { shared_ptr bookFromFile(std::string aPath); shared_ptr bookFromFile(QString aPath); bool isValidFileName(QString aName); + QByteArray fileHashAttr(QString aPath); + bool setFileHashAttr(QString aPath, QByteArray aHash); + QByteArray computeFileHash(QString aPath, BooksTask* aTask = NULL); + QByteArray computeFileHashAndSetAttr(QString aPath, BooksTask* aTask = NULL); } inline shared_ptr BooksUtil::bookFromFile(QString aPath)