1/* 2 * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7#include "Query.h" 8 9#include <file_systems/QueryParser.h> 10 11#include "AttributeCookie.h" 12#include "Directory.h" 13#include "Index.h" 14#include "Node.h" 15#include "Volume.h" 16 17 18// #pragma mark - QueryPolicy 19 20 21struct Query::QueryPolicy { 22 typedef Query Context; 23 typedef ::Node Entry; 24 typedef ::Node Node; 25 26 struct Index { 27 Query* query; 28 ::Index* index; 29 30 Index(Context* context) 31 : 32 query(context) 33 { 34 } 35 }; 36 37 struct IndexIterator : ::IndexIterator { 38 ::Index* index; 39 40 IndexIterator(::Index* index) 41 : 42 index(index) 43 { 44 } 45 }; 46 47 static const int32 kMaxFileNameLength = B_FILE_NAME_LENGTH; 48 49 // Entry interface 50 51 static ino_t EntryGetParentID(Entry* entry) 52 { 53 return entry->Parent()->ID(); 54 } 55 56 static Node* EntryGetNode(Entry* entry) 57 { 58 return entry; 59 } 60 61 static ino_t EntryGetNodeID(Entry* entry) 62 { 63 return entry->ID(); 64 } 65 66 static ssize_t EntryGetName(Entry* entry, void* buffer, size_t bufferSize) 67 { 68 const char* name = entry->Name(); 69 size_t nameLength = strlen(name); 70 if (nameLength >= bufferSize) 71 return B_BUFFER_OVERFLOW; 72 73 memcpy(buffer, name, nameLength + 1); 74 return nameLength + 1; 75 } 76 77 static const char* EntryGetNameNoCopy(Entry* entry, void* buffer, 78 size_t bufferSize) 79 { 80 return entry->Name(); 81 } 82 83 // Index interface 84 85 static status_t IndexSetTo(Index& index, const char* attribute) 86 { 87 index.index = index.query->fVolume->FindIndex(attribute); 88 return index.index != NULL ? B_OK : B_ENTRY_NOT_FOUND; 89 } 90 91 static void IndexUnset(Index& index) 92 { 93 index.index = NULL; 94 } 95 96 static int32 IndexGetWeightedScore(Index& index, int32 score) 97 { 98 // should be inversely proportional to the index size; max input score 99 // is 2048 100 static const int32 maxFactor = 1024 * 1024; 101 return score * (maxFactor 102 / std::min(maxFactor, 103 std::max((int32)1, index.index->CountEntries()))); 104 } 105 106 static type_code IndexGetType(Index& index) 107 { 108 return index.index->Type(); 109 } 110 111 static int32 IndexGetKeySize(Index& index) 112 { 113 return index.index->KeyLength(); 114 } 115 116 static IndexIterator* IndexCreateIterator(Index& index) 117 { 118 IndexIterator* iterator = new(std::nothrow) IndexIterator(index.index); 119 if (iterator == NULL) 120 return NULL; 121 122 if (!index.index->GetIterator(*iterator)) { 123 delete iterator; 124 return NULL; 125 } 126 127 return iterator; 128 } 129 130 // IndexIterator interface 131 132 static void IndexIteratorDelete(IndexIterator* indexIterator) 133 { 134 delete indexIterator; 135 } 136 137 static status_t IndexIteratorFind(IndexIterator* indexIterator, 138 const void* value, size_t size) 139 { 140 if (!indexIterator->index->Find(value, size, *indexIterator)) 141 return B_ENTRY_NOT_FOUND; 142 143 return B_OK; 144 } 145 146 static status_t IndexIteratorGetNextEntry(IndexIterator* indexIterator, 147 void* value, size_t* _valueLength, size_t bufferSize, Entry** _entry) 148 { 149 Node* node = indexIterator->Next(value, _valueLength); 150 if (node == NULL) 151 return B_ENTRY_NOT_FOUND; 152 153 *_entry = node; 154 return B_OK; 155 } 156 157 static void IndexIteratorSuspend(IndexIterator* indexIterator) 158 { 159 indexIterator->Suspend(); 160 } 161 162 static void IndexIteratorResume(IndexIterator* indexIterator) 163 { 164 indexIterator->Resume(); 165 } 166 167 // Node interface 168 169 static const off_t NodeGetSize(Node* node) 170 { 171 return node->FileSize(); 172 } 173 174 static time_t NodeGetLastModifiedTime(Node* node) 175 { 176 return node->ModifiedTime().tv_sec; 177 } 178 179 static status_t NodeGetAttribute(Node* node, const char* attribute, 180 void* buffer, size_t* _size, int32* _type) 181 { 182 // TODO: Creating a cookie is quite a bit of overhead. 183 AttributeCookie* cookie; 184 status_t error = node->OpenAttribute(attribute, O_RDONLY, cookie); 185 if (error != B_OK) 186 return error; 187 188 error = cookie->ReadAttribute(0, buffer, _size); 189 190 // also get the attribute type 191 if (error == B_OK) { 192 struct stat st; 193 error = cookie->ReadAttributeStat(&st); 194 if (error == B_OK) 195 *_type = st.st_type; 196 } 197 198 cookie->Close(); 199 delete cookie; 200 201 return error; 202 } 203 204 static Entry* NodeGetFirstReferrer(Node* node) 205 { 206 return node; 207 } 208 209 static Entry* NodeGetNextReferrer(Node* node, Entry* entry) 210 { 211 return NULL; 212 } 213 214 // Volume interface 215 216 static dev_t ContextGetVolumeID(Context* context) 217 { 218 return context->fVolume->ID(); 219 } 220}; 221 222 223// #pragma mark - Query 224 225 226Query::Query(Volume* volume) 227 : 228 fVolume(volume), 229 fImpl(NULL) 230{ 231} 232 233 234Query::~Query() 235{ 236 if (fImpl != NULL) { 237 if ((fImpl->Flags() & B_LIVE_QUERY) != 0) 238 fVolume->RemoveQuery(this); 239 240 delete fImpl; 241 } 242} 243 244 245/*static*/ status_t 246Query::Create(Volume* volume, const char* queryString, uint32 flags, 247 port_id port, uint32 token, Query*& _query) 248{ 249 Query* query = new(std::nothrow) Query(volume); 250 if (query == NULL) 251 return B_NO_MEMORY; 252 253 status_t error = query->_Init(queryString, flags, port, token); 254 if (error != B_OK) { 255 delete query; 256 return error; 257 } 258 259 _query = query; 260 return B_OK; 261} 262 263 264status_t 265Query::Rewind() 266{ 267 return fImpl->Rewind(); 268} 269 270 271status_t 272Query::GetNextEntry(struct dirent* entry, size_t size) 273{ 274 return fImpl->GetNextEntry(entry, size); 275} 276 277 278void 279Query::LiveUpdate(Node* node, const char* attribute, int32 type, 280 const void* oldKey, size_t oldLength, const void* newKey, size_t newLength) 281{ 282 fImpl->LiveUpdate(node, node, attribute, type, (const uint8*)oldKey, 283 oldLength, (const uint8*)newKey, newLength); 284} 285 286 287status_t 288Query::_Init(const char* queryString, uint32 flags, port_id port, uint32 token) 289{ 290 status_t error = QueryImpl::Create(this, queryString, flags, port, token, 291 fImpl); 292 if (error != B_OK) 293 return error; 294 295 if ((fImpl->Flags() & B_LIVE_QUERY) != 0) 296 fVolume->AddQuery(this); 297 298 return B_OK; 299} 300