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 108 struct Index { 109 Query* query; 110 ::Index* index; 111 112 Index(Context* context) 113 : 114 query(context) 115 { 116 } 117 }; 118 119 struct IndexIterator : ::IndexIterator { 120 IndexIterator(::Index* index) 121 : 122 ::IndexIterator(index) 123 { 124 } 125 }; 126 127 static const int32 kMaxFileNameLength = B_FILE_NAME_LENGTH; 128 129 // Entry interface 130 131 static ino_t EntryGetParentID(Entry* entry) 132 { 133 return entry->GetParent()->GetID(); 134 } 135 136 static Node* EntryGetNode(Entry* entry) 137 { 138 return entry->GetNode(); 139 } 140 141 static ino_t EntryGetNodeID(Entry* entry) 142 { 143 return entry->GetNode()->GetID(); 144 } 145 146 static ssize_t EntryGetName(Entry* entry, void* buffer, size_t bufferSize) 147 { 148 const char* name = entry->GetName(); 149 size_t nameLength = strlen(name); 150 if (nameLength >= bufferSize) 151 return B_BUFFER_OVERFLOW; 152 153 memcpy(buffer, name, nameLength + 1); 154 return nameLength + 1; 155 } 156 157 static const char* EntryGetNameNoCopy(Entry* entry, void* buffer, 158 size_t bufferSize) 159 { 160 return entry->GetName(); 161 } 162 163 // Index interface 164 165 static status_t IndexSetTo(Index& index, const char* attribute) 166 { 167 index.index = index.query->fVolume->FindIndex(attribute); 168 return index.index != NULL ? B_OK : B_ENTRY_NOT_FOUND; 169 } 170 171 static void IndexUnset(Index& index) 172 { 173 index.index = NULL; 174 } 175 176 static int32 IndexGetWeightedScore(Index& index, int32 score) 177 { 178 // should be inversely proportional to the index size; max input score 179 // is 2048 180 static const int32 maxFactor = (1024 * 1024) - 1; 181 return score * (maxFactor / 182 std::min(maxFactor, std::max((int32)1, index.index->CountEntries()))); 183 } 184 185 static type_code IndexGetType(Index& index) 186 { 187 return index.index->GetType(); 188 } 189 190 static int32 IndexGetKeySize(Index& index) 191 { 192 return index.index->GetKeyLength(); 193 } 194 195 static IndexIterator* IndexCreateIterator(Index& index) 196 { 197 IndexIterator* iterator = new(std::nothrow) IndexIterator(index.index); 198 if (iterator == NULL) 199 return NULL; 200 201 return iterator; 202 } 203 204 // IndexIterator interface 205 206 static void IndexIteratorDelete(IndexIterator* indexIterator) 207 { 208 delete indexIterator; 209 } 210 211 static status_t IndexIteratorFind(IndexIterator* indexIterator, 212 const void* value, size_t size) 213 { 214 return indexIterator->Find((const uint8*)value, size); 215 } 216 217 static status_t IndexIteratorGetNextEntry(IndexIterator* indexIterator, 218 void* value, size_t* _valueLength, size_t bufferSize, Entry** _entry) 219 { 220 return indexIterator->GetNextEntry((uint8*)value, _valueLength, _entry); 221 } 222 223 static void IndexIteratorSuspend(IndexIterator* indexIterator) 224 { 225 // Nothing to do. 226 } 227 228 static void IndexIteratorResume(IndexIterator* indexIterator) 229 { 230 // Nothing to do. 231 } 232 233 // Node interface 234 235 static const off_t NodeGetSize(Node* node) 236 { 237 return node->GetSize(); 238 } 239 240 static time_t NodeGetLastModifiedTime(Node* node) 241 { 242 return node->GetMTime(); 243 } 244 245 static status_t NodeGetAttribute(Node* node, const char* attribute, 246 void* buffer, size_t* _size, int32* _type) 247 { 248 Attribute* attr = NULL; 249 status_t error = node->FindAttribute(attribute, &attr); 250 if (error != B_OK) 251 return error; 252 253 *_type = attr->GetType(); 254 error = attr->ReadAt(0, buffer, *_size, _size); 255 256 return error; 257 } 258 259 static Entry* NodeGetFirstReferrer(Node* node) 260 { 261 return node->GetFirstReferrer(); 262 } 263 264 static Entry* NodeGetNextReferrer(Node* node, Entry* entry) 265 { 266 return node->GetNextReferrer(entry); 267 } 268 269 // Volume interface 270 271 static dev_t ContextGetVolumeID(Context* context) 272 { 273 return context->fVolume->GetID(); 274 } 275 }; 276 277 278 // #pragma mark - Query 279 280 281 Query::Query(Volume* volume) 282 : 283 fVolume(volume), 284 fImpl(NULL) 285 { 286 } 287 288 289 Query::~Query() 290 { 291 if (fImpl != NULL) { 292 if ((fImpl->Flags() & B_LIVE_QUERY) != 0) 293 fVolume->RemoveQuery(this); 294 295 delete fImpl; 296 } 297 } 298 299 300 /*static*/ status_t 301 Query::Create(Volume* volume, const char* queryString, uint32 flags, 302 port_id port, uint32 token, Query*& _query) 303 { 304 Query* query = new(std::nothrow) Query(volume); 305 if (query == NULL) 306 return B_NO_MEMORY; 307 308 status_t error = query->_Init(queryString, flags, port, token); 309 if (error != B_OK) { 310 delete query; 311 return error; 312 } 313 314 _query = query; 315 return B_OK; 316 } 317 318 319 status_t 320 Query::Rewind() 321 { 322 return fImpl->Rewind(); 323 } 324 325 326 status_t 327 Query::GetNextEntry(struct dirent* entry, size_t size) 328 { 329 return fImpl->GetNextEntry(entry, size); 330 } 331 332 333 void 334 Query::LiveUpdate(Entry* entry, Node* node, const char* attribute, int32 type, 335 const void* oldKey, size_t oldLength, const void* newKey, size_t newLength) 336 { 337 fImpl->LiveUpdate(entry, node, attribute, type, (const uint8*)oldKey, 338 oldLength, (const uint8*)newKey, newLength); 339 } 340 341 342 status_t 343 Query::_Init(const char* queryString, uint32 flags, port_id port, uint32 token) 344 { 345 status_t error = QueryImpl::Create(this, queryString, flags, port, token, 346 fImpl); 347 if (error != B_OK) 348 return error; 349 350 if ((fImpl->Flags() & B_LIVE_QUERY) != 0) 351 fVolume->AddQuery(this); 352 353 return B_OK; 354 } 355