File indexing completed on 2025-01-05 04:47:00

0001 /***************************************************************************
0002  *   SPDX-FileCopyrightText: 2009 Andras Mantia <amantia@kde.org>          *
0003  *   SPDX-FileCopyrightText: 2010 Volker Krause <vkrause@kde.org>          *
0004  *                                                                         *
0005  *   SPDX-License-Identifier: LGPL-2.0-or-later                            *
0006  ***************************************************************************/
0007 
0008 #include "parthelper.h"
0009 #include "dbconfig.h"
0010 #include "parttypehelper.h"
0011 #include "selectquerybuilder.h"
0012 
0013 #include "private/externalpartstorage_p.h"
0014 
0015 #include <QFile>
0016 
0017 #include "akonadiserver_debug.h"
0018 
0019 using namespace Akonadi;
0020 using namespace Akonadi::Server;
0021 
0022 void PartHelper::update(Part *part, const QByteArray &data, qint64 dataSize)
0023 {
0024     if (!part) {
0025         throw PartHelperException("Invalid part");
0026     }
0027 
0028     const bool storeExternal = dataSize > DbConfig::configuredDatabase()->sizeThreshold();
0029 
0030     QByteArray newFile;
0031     if (part->storage() == Part::External && storeExternal) {
0032         if (!ExternalPartStorage::self()->updatePartFile(data, part->data(), newFile)) {
0033             throw PartHelperException(QStringLiteral("Failed to update external payload part"));
0034         }
0035         part->setData(newFile);
0036     } else if (part->storage() != Part::External && storeExternal) {
0037         if (!ExternalPartStorage::self()->createPartFile(data, part->id(), newFile)) {
0038             throw PartHelperException(QStringLiteral("Failed to create external payload part"));
0039         }
0040         part->setData(newFile);
0041         part->setStorage(Part::External);
0042     } else {
0043         if (part->storage() == Part::External && !storeExternal) {
0044             const QString file = ExternalPartStorage::resolveAbsolutePath(part->data());
0045             ExternalPartStorage::self()->removePartFile(file);
0046         }
0047         part->setData(data);
0048         part->setStorage(Part::Internal);
0049     }
0050 
0051     part->setDatasize(dataSize);
0052     const bool result = part->update();
0053     if (!result) {
0054         throw PartHelperException("Failed to update database record");
0055     }
0056 }
0057 
0058 bool PartHelper::insert(Part *part, qint64 *insertId)
0059 {
0060     if (!part) {
0061         return false;
0062     }
0063 
0064     const bool storeInFile = part->datasize() > DbConfig::configuredDatabase()->sizeThreshold();
0065     // it is needed to insert first the metadata so a new id is generated for the part,
0066     // and we need this id for the payload file name
0067     QByteArray data;
0068     if (storeInFile) {
0069         data = part->data();
0070         part->setData(QByteArray());
0071         part->setStorage(Part::External);
0072     } else {
0073         part->setStorage(Part::Internal);
0074     }
0075 
0076     bool result = part->insert(insertId);
0077 
0078     if (storeInFile && result) {
0079         QByteArray filename;
0080         if (!ExternalPartStorage::self()->createPartFile(data, part->id(), filename)) {
0081             throw PartHelperException("Failed to create external payload part");
0082         }
0083         part->setData(filename);
0084         result = part->update();
0085     }
0086 
0087     return result;
0088 }
0089 
0090 bool PartHelper::remove(Part *part)
0091 {
0092     if (!part) {
0093         return false;
0094     }
0095 
0096     if (part->storage() == Part::External) {
0097         ExternalPartStorage::self()->removePartFile(ExternalPartStorage::resolveAbsolutePath(part->data()));
0098     }
0099     return part->remove();
0100 }
0101 
0102 bool PartHelper::remove(const QString &column, const QVariant &value)
0103 {
0104     SelectQueryBuilder<Part> builder;
0105     builder.addValueCondition(column, Query::Equals, value);
0106     builder.addValueCondition(Part::storageColumn(), Query::Equals, Part::External);
0107     builder.addValueCondition(Part::dataColumn(), Query::IsNot, QVariant());
0108     if (!builder.exec()) {
0109         //      qCDebug(AKONADISERVER_LOG) << "Error selecting records to be deleted from table"
0110         //          << Part::tableName() << builder.query().lastError().text();
0111         return false;
0112     }
0113     const Part::List parts = builder.result();
0114     Part::List::ConstIterator it = parts.constBegin();
0115     Part::List::ConstIterator end = parts.constEnd();
0116     for (; it != end; ++it) {
0117         ExternalPartStorage::self()->removePartFile(ExternalPartStorage::resolveAbsolutePath((*it).data()));
0118     }
0119     return Part::remove(column, value);
0120 }
0121 
0122 QByteArray PartHelper::translateData(const QByteArray &data, Part::Storage storage)
0123 {
0124     if (storage == Part::External || storage == Part::Foreign) {
0125         QFile file;
0126         if (storage == Part::External) {
0127             file.setFileName(ExternalPartStorage::resolveAbsolutePath(data));
0128         } else {
0129             file.setFileName(QString::fromUtf8(data));
0130         }
0131 
0132         if (file.open(QIODevice::ReadOnly)) {
0133             const QByteArray payload = file.readAll();
0134             file.close();
0135             return payload;
0136         } else {
0137             qCCritical(AKONADISERVER_LOG) << "Payload file " << file.fileName() << " could not be open for reading!";
0138             qCCritical(AKONADISERVER_LOG) << "Error: " << file.errorString();
0139             return QByteArray();
0140         }
0141     } else {
0142         // not external
0143         return data;
0144     }
0145 }
0146 
0147 QByteArray PartHelper::translateData(const Part &part)
0148 {
0149     return translateData(part.data(), part.storage());
0150 }
0151 
0152 bool PartHelper::truncate(Part &part)
0153 {
0154     if (part.storage() == Part::External) {
0155         ExternalPartStorage::self()->removePartFile(ExternalPartStorage::resolveAbsolutePath(part.data()));
0156     }
0157 
0158     part.setData(QByteArray());
0159     part.setDatasize(0);
0160     part.setStorage(Part::Internal);
0161     return part.update();
0162 }
0163 
0164 bool PartHelper::verify(Part &part)
0165 {
0166     if (part.storage() == Part::Internal) {
0167         return true;
0168     }
0169 
0170     QString fileName;
0171     if (part.storage() == Part::External) {
0172         fileName = ExternalPartStorage::resolveAbsolutePath(part.data());
0173     } else if (part.storage() == Part::Foreign) {
0174         fileName = QString::fromUtf8(part.data());
0175     } else {
0176         Q_ASSERT(false);
0177     }
0178 
0179     if (!QFile::exists(fileName)) {
0180         qCCritical(AKONADISERVER_LOG) << "Payload file" << fileName << "is missing, trying to recover.";
0181         part.setData(QByteArray());
0182         part.setDatasize(0);
0183         part.setStorage(Part::Internal);
0184         return part.update();
0185     }
0186 
0187     return true;
0188 }