[app] Moved hashing utilities to BooksUtil

This commit is contained in:
Slava Monich 2018-01-30 00:26:06 +02:00
parent 26510f1d9e
commit ed219c1af1
3 changed files with 104 additions and 66 deletions

View file

@ -35,20 +35,10 @@
#include "BooksStorage.h"
#include "BooksTask.h"
#include "BooksUtil.h"
#include "BooksDefs.h"
#include "HarbourDebug.h"
#include <QDir>
#include <QCryptographicHash>
#include <sys/xattr.h>
#include <linux/xattr.h>
#include <errno.h>
#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());

View file

@ -1,6 +1,6 @@
/*
* Copyright (C) 2015 Jolla Ltd.
* Contact: Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2015-2018 Jolla Ltd.
* Copyright (C) 2015-2018 Slava Monich <slava.monich@jolla.com>
*
* 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 <queue>
#include <QCryptographicHash>
#include <sys/xattr.h>
#include <linux/xattr.h>
#include <errno.h>
#define DIGEST_XATTR XATTR_USER_PREFIX BOOKS_APP_NAME ".md5-hash"
#define DIGEST_TYPE (QCryptographicHash::Md5)
#define DIGEST_SIZE (16)
shared_ptr<Book> BooksUtil::bookFromFile(std::string aPath)
{
shared_ptr<Book> book;
@ -78,6 +90,82 @@ shared_ptr<Book> 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() &&

View file

@ -1,6 +1,6 @@
/*
* Copyright (C) 2015 Jolla Ltd.
* Contact: Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2015-2018 Jolla Ltd.
* Copyright (C) 2015-2018 Slava Monich <slava.monich@jolla.com>
*
* 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 <QString>
class BooksTask;
namespace BooksUtil {
shared_ptr<Book> bookFromFile(std::string aPath);
shared_ptr<Book> 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<Book> BooksUtil::bookFromFile(QString aPath)