File indexing completed on 2024-04-21 03:51:39
0001 /* 0002 This file is part of the KDE Baloo project. 0003 SPDX-FileCopyrightText: 2015 Vishesh Handa <vhanda@kde.org> 0004 0005 SPDX-License-Identifier: LGPL-2.1-or-later 0006 */ 0007 0008 #include "documenturldb.h" 0009 #include "postingiterator.h" 0010 #include "enginedebug.h" 0011 0012 #include <algorithm> 0013 0014 using namespace Baloo; 0015 0016 DocumentUrlDB::DocumentUrlDB(MDB_dbi idTreeDb, MDB_dbi idFilenameDb, MDB_txn* txn) 0017 : m_txn(txn) 0018 , m_idFilenameDbi(idFilenameDb) 0019 , m_idTreeDbi(idTreeDb) 0020 { 0021 } 0022 0023 DocumentUrlDB::~DocumentUrlDB() 0024 { 0025 } 0026 0027 bool DocumentUrlDB::addPath(const QByteArray& url) 0028 { 0029 Q_ASSERT(!url.isEmpty()); 0030 Q_ASSERT(!url.endsWith('/')); 0031 if (url.isEmpty() || url.endsWith('/')) { 0032 return false; 0033 } 0034 0035 IdFilenameDB idFilenameDb(m_idFilenameDbi, m_txn); 0036 0037 QByteArray arr = url; 0038 quint64 id = filePathToId(arr); 0039 0040 while (id) { 0041 if (idFilenameDb.contains(id)) { 0042 return true; 0043 } 0044 0045 int pos = arr.lastIndexOf('/'); 0046 QByteArray name = arr.mid(pos + 1); 0047 0048 if (pos == 0) { 0049 add(id, 0, name); 0050 return true; 0051 } 0052 0053 arr.resize(pos); 0054 auto parentId = filePathToId(arr); 0055 if (!parentId) { 0056 return false; 0057 } 0058 add(id, parentId, name); 0059 0060 id = parentId; 0061 } 0062 return false; 0063 } 0064 0065 bool DocumentUrlDB::put(quint64 docId, quint64 parentId, const QByteArray& filename) 0066 { 0067 Q_ASSERT(docId); 0068 Q_ASSERT(!filename.contains('/')); 0069 Q_ASSERT(!filename.isEmpty()); 0070 if (!docId || filename.isEmpty() || filename.contains('/')) { 0071 return false; 0072 } 0073 0074 add(docId, parentId, filename); 0075 return true; 0076 } 0077 0078 void DocumentUrlDB::updateUrl(quint64 id, quint64 newParentId, const QByteArray& newName) 0079 { 0080 IdFilenameDB idFilenameDb(m_idFilenameDbi, m_txn); 0081 IdTreeDB idTreeDb(m_idTreeDbi, m_txn); 0082 0083 // Sanity checks 0084 auto path = idFilenameDb.get(id); 0085 if (path.parentId != newParentId) { 0086 // Remove from old parent 0087 QVector<quint64> subDocs = idTreeDb.get(path.parentId); 0088 if (subDocs.removeOne(id)) { 0089 idTreeDb.set(path.parentId, subDocs); 0090 } 0091 // Add to new parent 0092 subDocs = idTreeDb.get(newParentId); 0093 sortedIdInsert(subDocs, id); 0094 idTreeDb.set(newParentId, subDocs); 0095 } 0096 0097 if ((newName != path.name) || (newParentId != path.parentId)) { 0098 qCDebug(ENGINE) << id << "renaming" << path.name << "to" << newName; 0099 path.parentId = newParentId; 0100 path.name = newName; 0101 idFilenameDb.put(id, path); 0102 } 0103 } 0104 0105 void DocumentUrlDB::del(quint64 id) 0106 { 0107 if (!id) { 0108 qCWarning(ENGINE) << "del called with invalid docId"; 0109 return; 0110 } 0111 0112 IdFilenameDB idFilenameDb(m_idFilenameDbi, m_txn); 0113 IdTreeDB idTreeDb(m_idTreeDbi, m_txn); 0114 0115 auto path = idFilenameDb.get(id); 0116 0117 // Remove from parent 0118 QVector<quint64> subDocs = idTreeDb.get(path.parentId); 0119 if (subDocs.removeOne(id)) { 0120 idTreeDb.set(path.parentId, subDocs); 0121 } 0122 0123 qCDebug(ENGINE) << id << "deleting" << path.name; 0124 idFilenameDb.del(id); 0125 } 0126 0127 void DocumentUrlDB::add(quint64 id, quint64 parentId, const QByteArray& name) 0128 { 0129 if (!id || name.isEmpty()) { 0130 return; 0131 } 0132 0133 IdFilenameDB idFilenameDb(m_idFilenameDbi, m_txn); 0134 IdTreeDB idTreeDb(m_idTreeDbi, m_txn); 0135 0136 QVector<quint64> subDocs = idTreeDb.get(parentId); 0137 0138 // insert if not there 0139 sortedIdInsert(subDocs, id); 0140 0141 idTreeDb.set(parentId, subDocs); 0142 0143 // Update the IdFileName 0144 IdFilenameDB::FilePath path; 0145 path.parentId = parentId; 0146 path.name = name; 0147 0148 idFilenameDb.put(id, path); 0149 } 0150 0151 bool DocumentUrlDB::contains(quint64 docId) const 0152 { 0153 if (!docId) { 0154 return false; 0155 } 0156 0157 IdFilenameDB idFilenameDb(m_idFilenameDbi, m_txn); 0158 0159 return idFilenameDb.contains(docId); 0160 } 0161 0162 QByteArray DocumentUrlDB::get(quint64 docId) const 0163 { 0164 if (!docId) { 0165 return QByteArray(); 0166 } 0167 0168 IdFilenameDB idFilenameDb(m_idFilenameDbi, m_txn); 0169 0170 IdFilenameDB::FilePath path; 0171 if (!idFilenameDb.get(docId, path)) { 0172 return QByteArray(); 0173 } 0174 0175 QByteArray ret = '/' + path.name; 0176 quint64 id = path.parentId; 0177 // arbitrary path depth limit - we have to deal with 0178 // possibly corrupted DBs out in the wild 0179 int depth_limit = 512; 0180 0181 while (id) { 0182 if (!idFilenameDb.get(id, path)) { 0183 return QByteArray(); 0184 } 0185 if (!depth_limit--) { 0186 return QByteArray(); 0187 } 0188 path.name.prepend('/'); 0189 0190 ret.prepend(path.name); 0191 id = path.parentId; 0192 } 0193 0194 return ret; 0195 } 0196 0197 QVector<quint64> DocumentUrlDB::getChildren(quint64 docId) const 0198 { 0199 IdTreeDB idTreeDb(m_idTreeDbi, m_txn); 0200 return idTreeDb.get(docId); 0201 } 0202 0203 quint64 DocumentUrlDB::getId(quint64 docId, const QByteArray& fileName) const 0204 { 0205 if (fileName.isEmpty()) { 0206 return 0; 0207 } 0208 0209 IdFilenameDB idFilenameDb(m_idFilenameDbi, m_txn); 0210 IdTreeDB idTreeDb(m_idTreeDbi, m_txn); 0211 0212 const QVector<quint64> subFiles = idTreeDb.get(docId); 0213 IdFilenameDB::FilePath path; 0214 for (quint64 id : subFiles) { 0215 if (idFilenameDb.get(id, path) && (path.name == fileName)) { 0216 return id; 0217 } 0218 } 0219 0220 return 0; 0221 } 0222 0223 QMap<quint64, QByteArray> DocumentUrlDB::toTestMap() const 0224 { 0225 IdTreeDB idTreeDb(m_idTreeDbi, m_txn); 0226 0227 QMap<quint64, QVector<quint64>> idTreeMap = idTreeDb.toTestMap(); 0228 QSet<quint64> allIds; 0229 0230 for (auto it = idTreeMap.cbegin(); it != idTreeMap.cend(); it++) { 0231 allIds.insert(it.key()); 0232 for (quint64 id : it.value()) { 0233 allIds.insert(id); 0234 } 0235 } 0236 0237 QMap<quint64, QByteArray> map; 0238 for (quint64 id : allIds) { 0239 if (id) { 0240 QByteArray path = get(id); 0241 // FIXME: this prevents sanitizing 0242 // reactivate Q_ASSERT(!path.isEmpty()); 0243 map.insert(id, path); 0244 } 0245 } 0246 0247 return map; 0248 }