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 }