[app] Moved hashing utilities to BooksUtil
This commit is contained in:
parent
26510f1d9e
commit
ed219c1af1
3 changed files with 104 additions and 66 deletions
|
@ -35,20 +35,10 @@
|
||||||
#include "BooksStorage.h"
|
#include "BooksStorage.h"
|
||||||
#include "BooksTask.h"
|
#include "BooksTask.h"
|
||||||
#include "BooksUtil.h"
|
#include "BooksUtil.h"
|
||||||
#include "BooksDefs.h"
|
|
||||||
|
|
||||||
#include "HarbourDebug.h"
|
#include "HarbourDebug.h"
|
||||||
|
|
||||||
#include <QDir>
|
#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 {
|
enum BooksImportRole {
|
||||||
BooksImportRoleTitle = Qt::UserRole,
|
BooksImportRoleTitle = Qt::UserRole,
|
||||||
|
@ -103,7 +93,6 @@ public:
|
||||||
void performTask();
|
void performTask();
|
||||||
void scanDir(QDir aDir);
|
void scanDir(QDir aDir);
|
||||||
bool isDuplicate(QString aPath, QFileInfoList aFileList);
|
bool isDuplicate(QString aPath, QFileInfoList aFileList);
|
||||||
QByteArray calculateFileHash(QString aPath);
|
|
||||||
QByteArray getFileHash(QString aPath);
|
QByteArray getFileHash(QString aPath);
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
|
@ -134,60 +123,16 @@ BooksImportModel::Task::~Task()
|
||||||
delete [] iBuf;
|
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)
|
QByteArray BooksImportModel::Task::getFileHash(QString aPath)
|
||||||
{
|
{
|
||||||
if (iFileHash.contains(aPath)) {
|
if (iFileHash.contains(aPath)) {
|
||||||
return iFileHash.value(aPath);
|
return iFileHash.value(aPath);
|
||||||
} else {
|
} else {
|
||||||
QByteArray hash;
|
QByteArray hash(BooksUtil::fileHashAttr(aPath));
|
||||||
char attr[DIGEST_SIZE];
|
if (hash.isEmpty()) {
|
||||||
QByteArray fname = aPath.toLocal8Bit();
|
hash = BooksUtil::computeFileHashAndSetAttr(aPath, this);
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (hash.size() == DIGEST_SIZE) {
|
if (!hash.isEmpty()) {
|
||||||
iFileHash.insert(aPath, hash);
|
iFileHash.insert(aPath, hash);
|
||||||
iHashFile.insert(hash, aPath);
|
iHashFile.insert(hash, aPath);
|
||||||
}
|
}
|
||||||
|
@ -249,7 +194,6 @@ void BooksImportModel::Task::scanDir(QDir aDir)
|
||||||
if (!isDuplicate(filePath, iDestFiles) &&
|
if (!isDuplicate(filePath, iDestFiles) &&
|
||||||
!isDuplicate(filePath, iSrcFiles)) {
|
!isDuplicate(filePath, iSrcFiles)) {
|
||||||
BooksBook* newBook = new BooksBook(dummy, QString(), book);
|
BooksBook* newBook = new BooksBook(dummy, QString(), book);
|
||||||
newBook->moveToThread(thread());
|
|
||||||
iBooks.append(newBook);
|
iBooks.append(newBook);
|
||||||
iSrcFiles.append(fileInfo);
|
iSrcFiles.append(fileInfo);
|
||||||
HDEBUG("found" << path.c_str() << newBook->title());
|
HDEBUG("found" << path.c_str() << newBook->title());
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2015 Jolla Ltd.
|
* Copyright (C) 2015-2018 Jolla Ltd.
|
||||||
* Contact: Slava Monich <slava.monich@jolla.com>
|
* Copyright (C) 2015-2018 Slava Monich <slava.monich@jolla.com>
|
||||||
*
|
*
|
||||||
* You may use this file under the terms of the BSD license as follows:
|
* 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
|
* notice, this list of conditions and the following disclaimer in
|
||||||
* the documentation and/or other materials provided with the
|
* the documentation and/or other materials provided with the
|
||||||
* distribution.
|
* 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
|
* may be used to endorse or promote products derived from this
|
||||||
* software without specific prior written permission.
|
* software without specific prior written permission.
|
||||||
*
|
*
|
||||||
|
@ -32,6 +32,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "BooksUtil.h"
|
#include "BooksUtil.h"
|
||||||
|
#include "BooksDefs.h"
|
||||||
|
#include "BooksTask.h"
|
||||||
#include "HarbourDebug.h"
|
#include "HarbourDebug.h"
|
||||||
|
|
||||||
#include "ZLDir.h"
|
#include "ZLDir.h"
|
||||||
|
@ -39,6 +41,16 @@
|
||||||
|
|
||||||
#include <queue>
|
#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> BooksUtil::bookFromFile(std::string aPath)
|
||||||
{
|
{
|
||||||
shared_ptr<Book> book;
|
shared_ptr<Book> book;
|
||||||
|
@ -78,6 +90,82 @@ shared_ptr<Book> BooksUtil::bookFromFile(std::string aPath)
|
||||||
return book;
|
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)
|
bool BooksUtil::isValidFileName(QString aName)
|
||||||
{
|
{
|
||||||
return !aName.isEmpty() &&
|
return !aName.isEmpty() &&
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2015 Jolla Ltd.
|
* Copyright (C) 2015-2018 Jolla Ltd.
|
||||||
* Contact: Slava Monich <slava.monich@jolla.com>
|
* Copyright (C) 2015-2018 Slava Monich <slava.monich@jolla.com>
|
||||||
*
|
*
|
||||||
* You may use this file under the terms of the BSD license as follows:
|
* 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
|
* notice, this list of conditions and the following disclaimer in
|
||||||
* the documentation and/or other materials provided with the
|
* the documentation and/or other materials provided with the
|
||||||
* distribution.
|
* 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
|
* may be used to endorse or promote products derived from this
|
||||||
* software without specific prior written permission.
|
* software without specific prior written permission.
|
||||||
*
|
*
|
||||||
|
@ -40,10 +40,16 @@
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
|
class BooksTask;
|
||||||
|
|
||||||
namespace BooksUtil {
|
namespace BooksUtil {
|
||||||
shared_ptr<Book> bookFromFile(std::string aPath);
|
shared_ptr<Book> bookFromFile(std::string aPath);
|
||||||
shared_ptr<Book> bookFromFile(QString aPath);
|
shared_ptr<Book> bookFromFile(QString aPath);
|
||||||
bool isValidFileName(QString aName);
|
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)
|
inline shared_ptr<Book> BooksUtil::bookFromFile(QString aPath)
|
||||||
|
|
Loading…
Reference in a new issue