1 /* 2 * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Copyright 2023, Haiku, Inc. All rights reserved. 4 * Distributed under the terms of the MIT License. 5 */ 6 7 #include "Query.h" 8 9 #include "Directory.h" 10 #include "Entry.h" 11 #include "Node.h" 12 #include "Volume.h" 13 #include "Index.h" 14 15 #include <file_systems/QueryParser.h> 16 17 18 // #pragma mark - IndexIterator 19 20 21 class IndexIterator { 22 public: 23 IndexIterator(Index *index); 24 25 status_t Find(const uint8 *const key, size_t keyLength); 26 status_t Rewind(); 27 status_t GetNextEntry(uint8 *buffer, size_t *keyLength, Entry **entry); 28 29 Index* GetIndex() const { return fIndex; } 30 31 private: 32 Index *fIndex; 33 IndexEntryIterator fIterator; 34 bool fInitialized; 35 }; 36 37 38 IndexIterator::IndexIterator(Index *index) 39 : fIndex(index), 40 fIterator(), 41 fInitialized(false) 42 { 43 } 44 45 46 status_t 47 IndexIterator::Find(const uint8 *const key, size_t keyLength) 48 { 49 status_t error = B_ENTRY_NOT_FOUND; 50 if (fIndex) { 51 // TODO: We actually don't want an exact Find() here, but rather a 52 // FindClose(). 53 fInitialized = fIndex->Find(key, keyLength, &fIterator); 54 if (fInitialized) 55 error = B_OK; 56 } 57 return error; 58 } 59 60 61 status_t 62 IndexIterator::Rewind() 63 { 64 status_t error = B_ENTRY_NOT_FOUND; 65 if (fIndex) { 66 fInitialized = fIndex->GetIterator(&fIterator); 67 if (fInitialized) 68 error = B_OK; 69 } 70 return error; 71 } 72 73 74 status_t 75 IndexIterator::GetNextEntry(uint8 *buffer, size_t *_keyLength, Entry **_entry) 76 { 77 status_t error = B_ENTRY_NOT_FOUND; 78 if (fIndex) { 79 // init iterator, if not done yet 80 if (!fInitialized) { 81 fIndex->GetIterator(&fIterator); 82 fInitialized = true; 83 } 84 85 // get key 86 size_t keyLength; 87 if (Entry *entry = fIterator.GetCurrent(buffer, &keyLength)) { 88 *_keyLength = keyLength; 89 *_entry = entry; 90 error = B_OK; 91 } 92 93 // get next entry 94 fIterator.GetNext(); 95 } 96 return error; 97 } 98 99 100 // #pragma mark - QueryPolicy 101 102 103 struct Query::QueryPolicy { 104 typedef Query Context; 105 typedef ::Entry Entry; 106 typedef ::Node Node; 107 typedef void* NodeHolder; 108 109 struct Index { 110 Query* query; 111 ::Index* index; 112 113 Index(Context* context) 114 : 115 query(context) 116 { 117 } 118 }; 119 120 struct IndexIterator : ::IndexIterator { 121 Entry* entry; 122 123 IndexIterator(::Index* index) 124 : 125 ::IndexIterator(index) 126 { 127 } 128 }; 129 130 static const int32 kMaxFileNameLength = B_FILE_NAME_LENGTH; 131 132 // Entry interface 133 134 static ino_t EntryGetParentID(Entry* entry) 135 { 136 return entry->GetParent()->GetID(); 137 } 138 139 static Node* EntryGetNode(Entry* entry) 140 { 141 return entry->GetNode(); 142 } 143 144 static ino_t EntryGetNodeID(Entry* entry) 145 { 146 return entry->GetNode()->GetID(); 147 } 148 149 static ssize_t EntryGetName(Entry* entry, void* buffer, size_t bufferSize) 150 { 151 const char* name = entry->GetName(); 152 size_t nameLength = strlen(name); 153 if (nameLength >= bufferSize) 154 return B_BUFFER_OVERFLOW; 155 156 memcpy(buffer, name, nameLength + 1); 157 return nameLength + 1; 158 } 159 160 static const char* EntryGetNameNoCopy(NodeHolder& holder, Entry* entry) 161 { 162 return entry->GetName(); 163 } 164 165 // Index interface 166 167 static status_t IndexSetTo(Index& index, const char* attribute) 168 { 169 index.index = index.query->fVolume->FindIndex(attribute); 170 return index.index != NULL ? B_OK : B_ENTRY_NOT_FOUND; 171 } 172 173 static void IndexUnset(Index& index) 174 { 175 index.index = NULL; 176 } 177 178 static int32 IndexGetWeightedScore(Index& index, int32 score) 179 { 180 // should be inversely proportional to the index size; max input score 181 // is 2048 182 static const int32 maxFactor = (1024 * 1024) - 1; 183 return score * (maxFactor / 184 std::min(maxFactor, std::max((int32)1, index.index->CountEntries()))); 185 } 186 187 static type_code IndexGetType(Index& index) 188 { 189 return index.index->GetType(); 190 } 191 192 static int32 IndexGetKeySize(Index& index) 193 { 194 return index.index->GetKeyLength(); 195 } 196 197 static IndexIterator* IndexCreateIterator(Index& index) 198 { 199 IndexIterator* iterator = new(std::nothrow) IndexIterator(index.index); 200 if (iterator == NULL) 201 return NULL; 202 203 return iterator; 204 } 205 206 // IndexIterator interface 207 208 static void IndexIteratorDelete(IndexIterator* indexIterator) 209 { 210 delete indexIterator; 211 } 212 213 static status_t IndexIteratorFind(IndexIterator* indexIterator, 214 const void* value, size_t size) 215 { 216 return indexIterator->Find((const uint8*)value, size); 217 } 218 219 static status_t IndexIteratorFetchNextEntry(IndexIterator* indexIterator, 220 void* value, size_t* _valueLength, size_t bufferSize, size_t* duplicate) 221 { 222 return indexIterator->GetNextEntry((uint8*)value, _valueLength, &indexIterator->entry); 223 } 224 225 static status_t IndexIteratorGetEntry(Context* context, IndexIterator* indexIterator, 226 NodeHolder& holder, Entry** _entry) 227 { 228 *_entry = indexIterator->entry; 229 return B_OK; 230 } 231 232 static void IndexIteratorSkipDuplicates(IndexIterator* indexIterator) 233 { 234 // Nothing to do. 235 } 236 237 static void IndexIteratorSuspend(IndexIterator* indexIterator) 238 { 239 // Nothing to do. 240 } 241 242 static void IndexIteratorResume(IndexIterator* indexIterator) 243 { 244 // Nothing to do. 245 } 246 247 // Node interface 248 249 static const off_t NodeGetSize(Node* node) 250 { 251 return node->GetSize(); 252 } 253 254 static time_t NodeGetLastModifiedTime(Node* node) 255 { 256 return node->GetMTime(); 257 } 258 259 static status_t NodeGetAttribute(NodeHolder& nodeHolder, Node* node, 260 const char* attribute, void* buffer, size_t* _size, int32* _type) 261 { 262 Attribute* attr = NULL; 263 status_t error = node->FindAttribute(attribute, &attr); 264 if (error != B_OK) 265 return error; 266 267 *_type = attr->GetType(); 268 error = attr->ReadAt(0, buffer, *_size, _size); 269 270 return error; 271 } 272 273 static Entry* NodeGetFirstReferrer(Node* node) 274 { 275 return node->GetFirstReferrer(); 276 } 277 278 static Entry* NodeGetNextReferrer(Node* node, Entry* entry) 279 { 280 return node->GetNextReferrer(entry); 281 } 282 283 // Volume interface 284 285 static dev_t ContextGetVolumeID(Context* context) 286 { 287 return context->fVolume->GetID(); 288 } 289 }; 290 291 292 // #pragma mark - Query 293 294 295 Query::Query(Volume* volume) 296 : 297 fVolume(volume), 298 fImpl(NULL) 299 { 300 } 301 302 303 Query::~Query() 304 { 305 if (fImpl != NULL) { 306 if ((fImpl->Flags() & B_LIVE_QUERY) != 0) 307 fVolume->RemoveQuery(this); 308 309 delete fImpl; 310 } 311 } 312 313 314 /*static*/ status_t 315 Query::Create(Volume* volume, const char* queryString, uint32 flags, 316 port_id port, uint32 token, Query*& _query) 317 { 318 Query* query = new(std::nothrow) Query(volume); 319 if (query == NULL) 320 return B_NO_MEMORY; 321 322 status_t error = query->_Init(queryString, flags, port, token); 323 if (error != B_OK) { 324 delete query; 325 return error; 326 } 327 328 _query = query; 329 return B_OK; 330 } 331 332 333 status_t 334 Query::Rewind() 335 { 336 return fImpl->Rewind(); 337 } 338 339 340 status_t 341 Query::GetNextEntry(struct dirent* entry, size_t size) 342 { 343 return fImpl->GetNextEntry(entry, size); 344 } 345 346 347 void 348 Query::LiveUpdate(Entry* entry, Node* node, const char* attribute, int32 type, 349 const void* oldKey, size_t oldLength, const void* newKey, size_t newLength) 350 { 351 fImpl->LiveUpdate(entry, node, attribute, type, (const uint8*)oldKey, 352 oldLength, (const uint8*)newKey, newLength); 353 } 354 355 356 status_t 357 Query::_Init(const char* queryString, uint32 flags, port_id port, uint32 token) 358 { 359 status_t error = QueryImpl::Create(this, queryString, flags, port, token, 360 fImpl); 361 if (error != B_OK) 362 return error; 363 364 if ((fImpl->Flags() & B_LIVE_QUERY) != 0) 365 fVolume->AddQuery(this); 366 367 return B_OK; 368 } 369