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 21 struct Query::QueryPolicy { 22 typedef Query Context; 23 typedef ::Node Entry; 24 typedef ::Node Node; 25 typedef void* NodeHolder; 26 27 struct Index { 28 Query* query; 29 ::Index* index; 30 31 Index(Context* context) 32 : 33 query(context) 34 { 35 } 36 }; 37 38 struct IndexIterator : ::IndexIterator { 39 ::Index* index; 40 Entry* entry; 41 42 IndexIterator(::Index* index) 43 : 44 index(index) 45 { 46 } 47 }; 48 49 static const int32 kMaxFileNameLength = B_FILE_NAME_LENGTH; 50 51 // Entry interface 52 53 static ino_t EntryGetParentID(Entry* entry) 54 { 55 return entry->Parent()->ID(); 56 } 57 58 static Node* EntryGetNode(Entry* entry) 59 { 60 return entry; 61 } 62 63 static ino_t EntryGetNodeID(Entry* entry) 64 { 65 return entry->ID(); 66 } 67 68 static ssize_t EntryGetName(Entry* entry, void* buffer, size_t bufferSize) 69 { 70 const char* name = entry->Name(); 71 size_t nameLength = strlen(name); 72 if (nameLength >= bufferSize) 73 return B_BUFFER_OVERFLOW; 74 75 memcpy(buffer, name, nameLength + 1); 76 return nameLength + 1; 77 } 78 79 static const char* EntryGetNameNoCopy(NodeHolder& holder, Entry* entry) 80 { 81 return entry->Name(); 82 } 83 84 // Index interface 85 86 static status_t IndexSetTo(Index& index, const char* attribute) 87 { 88 index.index = index.query->fVolume->FindIndex(StringKey(attribute)); 89 return index.index != NULL ? B_OK : B_ENTRY_NOT_FOUND; 90 } 91 92 static void IndexUnset(Index& index) 93 { 94 index.index = NULL; 95 } 96 97 static int32 IndexGetWeightedScore(Index& index, int32 score) 98 { 99 // should be inversely proportional to the index size; max input score 100 // is 2048 101 static const int32 maxFactor = (1024 * 1024) - 1; 102 return score * (maxFactor / 103 std::min(maxFactor, 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 IndexIteratorFetchNextEntry(IndexIterator* indexIterator, 147 void* value, size_t* _valueLength, size_t bufferSize, size_t* duplicate) 148 { 149 Node* node = indexIterator->Next(value, _valueLength); 150 if (node == NULL) 151 return B_ENTRY_NOT_FOUND; 152 153 indexIterator->entry = node; 154 return B_OK; 155 } 156 157 static status_t IndexIteratorGetEntry(Context* context, IndexIterator* indexIterator, 158 NodeHolder& holder, Entry** _entry) 159 { 160 *_entry = indexIterator->entry; 161 return B_OK; 162 } 163 164 static void IndexIteratorSkipDuplicates(IndexIterator* indexIterator) 165 { 166 // Nothing to do. 167 } 168 169 static void IndexIteratorSuspend(IndexIterator* indexIterator) 170 { 171 indexIterator->Suspend(); 172 } 173 174 static void IndexIteratorResume(IndexIterator* indexIterator) 175 { 176 indexIterator->Resume(); 177 } 178 179 // Node interface 180 181 static const off_t NodeGetSize(Node* node) 182 { 183 return node->FileSize(); 184 } 185 186 static time_t NodeGetLastModifiedTime(Node* node) 187 { 188 return node->ModifiedTime().tv_sec; 189 } 190 191 static status_t NodeGetAttribute(NodeHolder& nodeHolder, Node* node, 192 const char* attribute, void* buffer, size_t* _size, int32* _type) 193 { 194 // TODO: Creating a cookie is quite a bit of overhead. 195 AttributeCookie* cookie; 196 status_t error = node->OpenAttribute(StringKey(attribute), O_RDONLY, 197 cookie); 198 if (error != B_OK) 199 return error; 200 201 error = cookie->ReadAttribute(0, buffer, _size); 202 203 // also get the attribute type 204 if (error == B_OK) { 205 struct stat st; 206 error = cookie->ReadAttributeStat(&st); 207 if (error == B_OK) 208 *_type = st.st_type; 209 } 210 211 cookie->Close(); 212 delete cookie; 213 214 return error; 215 } 216 217 static Entry* NodeGetFirstReferrer(Node* node) 218 { 219 return node; 220 } 221 222 static Entry* NodeGetNextReferrer(Node* node, Entry* entry) 223 { 224 return NULL; 225 } 226 227 // Volume interface 228 229 static dev_t ContextGetVolumeID(Context* context) 230 { 231 return context->fVolume->ID(); 232 } 233 }; 234 235 236 // #pragma mark - Query 237 238 239 Query::Query(Volume* volume) 240 : 241 fVolume(volume), 242 fImpl(NULL) 243 { 244 } 245 246 247 Query::~Query() 248 { 249 if (fImpl != NULL) { 250 if ((fImpl->Flags() & B_LIVE_QUERY) != 0) 251 fVolume->RemoveQuery(this); 252 253 delete fImpl; 254 } 255 } 256 257 258 /*static*/ status_t 259 Query::Create(Volume* volume, const char* queryString, uint32 flags, 260 port_id port, uint32 token, Query*& _query) 261 { 262 Query* query = new(std::nothrow) Query(volume); 263 if (query == NULL) 264 return B_NO_MEMORY; 265 266 status_t error = query->_Init(queryString, flags, port, token); 267 if (error != B_OK) { 268 delete query; 269 return error; 270 } 271 272 _query = query; 273 return B_OK; 274 } 275 276 277 status_t 278 Query::Rewind() 279 { 280 return fImpl->Rewind(); 281 } 282 283 284 status_t 285 Query::GetNextEntry(struct dirent* entry, size_t size) 286 { 287 return fImpl->GetNextEntry(entry, size); 288 } 289 290 291 void 292 Query::LiveUpdate(Node* node, const char* attribute, int32 type, 293 const void* oldKey, size_t oldLength, const void* newKey, size_t newLength) 294 { 295 fImpl->LiveUpdate(node, node, attribute, type, (const uint8*)oldKey, 296 oldLength, (const uint8*)newKey, newLength); 297 } 298 299 300 status_t 301 Query::_Init(const char* queryString, uint32 flags, port_id port, uint32 token) 302 { 303 status_t error = QueryImpl::Create(this, queryString, flags, port, token, 304 fImpl); 305 if (error != B_OK) 306 return error; 307 308 if ((fImpl->Flags() & B_LIVE_QUERY) != 0) 309 fVolume->AddQuery(this); 310 311 return B_OK; 312 } 313