1/* 2 * Copyright 2007, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * All rights reserved. Distributed under the terms of the MIT license. 4 */ 5 6#include <TypeConstants.h> 7 8#include "DebugSupport.h" 9#include "Entry.h" 10#include "IndexImpl.h" 11#include "NameIndex.h" 12#include "ramfs.h" 13#include "Volume.h" 14 15// NameIndexPrimaryKey 16class NameIndexPrimaryKey { 17public: 18 NameIndexPrimaryKey(const Entry *entry, 19 const char *name = NULL) 20 : entry(entry), name(name ? name : entry->GetName()) {} 21 NameIndexPrimaryKey(const char *name) 22 : entry(NULL), name(name) {} 23 24 const Entry *entry; 25 const char *name; 26}; 27 28// NameIndexGetPrimaryKey 29class NameIndexGetPrimaryKey { 30public: 31 inline NameIndexPrimaryKey operator()(const Entry *a) 32 { 33 return NameIndexPrimaryKey(a); 34 } 35 36 inline NameIndexPrimaryKey operator()(const Entry *a) const 37 { 38 return NameIndexPrimaryKey(a); 39 } 40}; 41 42 43// NameIndexPrimaryKeyCompare 44class NameIndexPrimaryKeyCompare 45{ 46public: 47 inline int operator()(const NameIndexPrimaryKey &a, 48 const NameIndexPrimaryKey &b) const 49 { 50 if (a.entry != NULL && a.entry == b.entry) 51 return 0; 52 return strcmp(a.name, b.name); 53 } 54}; 55 56 57// EntryTree 58 59typedef TwoKeyAVLTree<Entry*, NameIndexPrimaryKey, NameIndexPrimaryKeyCompare, 60 NameIndexGetPrimaryKey> 61 _EntryTree; 62 63class NameIndex::EntryTree : public _EntryTree {}; 64 65 66// NameIndexEntryIterator 67class NameIndexEntryIterator : public AbstractIndexEntryIterator, 68 public EntryListener { 69public: 70 NameIndexEntryIterator(); 71 virtual ~NameIndexEntryIterator(); 72 73 virtual Entry *GetCurrent(); 74 virtual Entry *GetCurrent(uint8 *buffer, size_t *keyLength); 75 virtual Entry *GetPrevious(); 76 virtual Entry *GetNext(); 77 78 virtual status_t Suspend(); 79 virtual status_t Resume(); 80 81 bool SetTo(NameIndex *index, const char *name, bool ignoreValue = false); 82 83 virtual void EntryRemoved(Entry *entry); 84 85private: 86 friend class NameIndex; 87 88 typedef AbstractIndexEntryIterator BaseClass; 89 90private: 91 NameIndex *fIndex; 92 NameIndex::EntryTree::Iterator fIterator; 93 bool fSuspended; 94 bool fIsNext; 95}; 96 97 98// NameIndex 99 100// constructor 101NameIndex::NameIndex(Volume *volume) 102 : Index(volume, "name", B_STRING_TYPE, false), 103 fEntries(new(nothrow) EntryTree) 104{ 105 if (fInitStatus == B_OK && !fEntries) 106 fInitStatus = B_NO_MEMORY; 107 if (fInitStatus == B_OK) { 108 fInitStatus = fVolume->AddEntryListener(this, 109 NULL, ENTRY_LISTEN_ANY_ENTRY | ENTRY_LISTEN_ALL); 110 } 111} 112 113// destructor 114NameIndex::~NameIndex() 115{ 116 if (fVolume) 117 fVolume->RemoveEntryListener(this, NULL); 118 if (fEntries) 119 delete fEntries; 120 // Actually we would need to maintain a list of iterators and unset the 121 // still existing iterators here. But since the name index is deleted 122 // when the volume is unmounted, there shouldn't be any iterators left 123 // anymore. 124} 125 126// CountEntries 127int32 128NameIndex::CountEntries() const 129{ 130 return fEntries->CountItems(); 131} 132 133// Changed 134status_t 135NameIndex::Changed(Entry *entry, const char *oldName) 136{ 137 status_t error = B_BAD_VALUE; 138 if (entry && oldName) { 139 EntryTree::Iterator it; 140 Entry **foundEntry 141 = fEntries->Find(NameIndexPrimaryKey(entry, oldName), entry, &it); 142 if (foundEntry && *foundEntry == entry) { 143 it.Remove(); 144 error = fEntries->Insert(entry); 145 146 // udpate live queries 147 _UpdateLiveQueries(entry, oldName, entry->GetName()); 148 } 149 } 150 return error; 151} 152 153// EntryAdded 154void 155NameIndex::EntryAdded(Entry *entry) 156{ 157 if (entry) { 158 fEntries->Insert(entry); 159 160 // udpate live queries 161 _UpdateLiveQueries(entry, NULL, entry->GetName()); 162 } 163} 164 165// EntryRemoved 166void 167NameIndex::EntryRemoved(Entry *entry) 168{ 169 if (entry) { 170 fEntries->Remove(entry, entry); 171 172 // udpate live queries 173 _UpdateLiveQueries(entry, entry->GetName(), NULL); 174 } 175} 176 177// InternalGetIterator 178AbstractIndexEntryIterator * 179NameIndex::InternalGetIterator() 180{ 181 NameIndexEntryIterator *iterator = new(nothrow) NameIndexEntryIterator; 182 if (iterator) { 183 if (!iterator->SetTo(this, NULL, true)) { 184 delete iterator; 185 iterator = NULL; 186 } 187 } 188 return iterator; 189} 190 191// InternalFind 192AbstractIndexEntryIterator * 193NameIndex::InternalFind(const uint8 *key, size_t length) 194{ 195 if (!key || length == 0) 196 return NULL; 197 198 // if the key is not null-terminated, copy it 199 uint8 clonedKey[kMaxIndexKeyLength]; 200 if (key[length - 1] != '\0') { 201 if (length >= kMaxIndexKeyLength) 202 length = kMaxIndexKeyLength - 1; 203 204 memcpy(clonedKey, key, length); 205 clonedKey[length] = '\0'; 206 length++; 207 key = clonedKey; 208 } 209 210 NameIndexEntryIterator *iterator = new(nothrow) NameIndexEntryIterator; 211 if (iterator) { 212 if (!iterator->SetTo(this, (const char *)key)) { 213 delete iterator; 214 iterator = NULL; 215 } 216 } 217 return iterator; 218} 219 220// _UpdateLiveQueries 221void 222NameIndex::_UpdateLiveQueries(Entry* entry, const char* oldName, 223 const char* newName) 224{ 225 fVolume->UpdateLiveQueries(entry, entry->GetNode(), GetName(), 226 GetType(), (const uint8*)oldName, (oldName ? strlen(oldName) : 0), 227 (const uint8*)newName, (newName ? strlen(newName) : 0)); 228} 229 230 231// NameIndexEntryIterator 232 233// constructor 234NameIndexEntryIterator::NameIndexEntryIterator() 235 : AbstractIndexEntryIterator(), 236 fIndex(NULL), 237 fIterator(), 238 fSuspended(false), 239 fIsNext(false) 240{ 241} 242 243// destructor 244NameIndexEntryIterator::~NameIndexEntryIterator() 245{ 246 SetTo(NULL, NULL); 247} 248 249// GetCurrent 250Entry * 251NameIndexEntryIterator::GetCurrent() 252{ 253 return (fIndex && fIterator.GetCurrent() ? *fIterator.GetCurrent() : NULL); 254} 255 256// GetCurrent 257Entry * 258NameIndexEntryIterator::GetCurrent(uint8 *buffer, size_t *keyLength) 259{ 260 Entry *entry = GetCurrent(); 261 if (entry) { 262 strncpy((char*)buffer, entry->GetName(), kMaxIndexKeyLength); 263 *keyLength = strlen(entry->GetName()); 264 } 265 return entry; 266} 267 268// GetPrevious 269Entry * 270NameIndexEntryIterator::GetPrevious() 271{ 272 if (fSuspended) 273 return NULL; 274 if (!(fIterator.GetCurrent() && fIsNext)) 275 fIterator.GetPrevious(); 276 fIsNext = false; 277 return (fIndex && fIterator.GetCurrent() ? *fIterator.GetCurrent() : NULL); 278} 279 280// GetNext 281Entry * 282NameIndexEntryIterator::GetNext() 283{ 284 if (fSuspended) 285 return NULL; 286 if (!(fIterator.GetCurrent() && fIsNext)) 287 fIterator.GetNext(); 288 fIsNext = false; 289 return (fIndex && fIterator.GetCurrent() ? *fIterator.GetCurrent() : NULL); 290} 291 292// Suspend 293status_t 294NameIndexEntryIterator::Suspend() 295{ 296 status_t error = (!fSuspended ? B_OK : B_BAD_VALUE); 297 if (error == B_OK) { 298 if (fIterator.GetCurrent()) { 299 error = fIndex->GetVolume()->AddEntryListener(this, 300 *fIterator.GetCurrent(), ENTRY_LISTEN_REMOVED); 301 } 302 if (error == B_OK) 303 fSuspended = true; 304 } 305 return error; 306} 307 308// Resume 309status_t 310NameIndexEntryIterator::Resume() 311{ 312 status_t error = (fSuspended ? B_OK : B_BAD_VALUE); 313 if (error == B_OK) { 314 if (fIterator.GetCurrent()) { 315 error = fIndex->GetVolume()->RemoveEntryListener(this, 316 *fIterator.GetCurrent()); 317 } 318 if (error == B_OK) 319 fSuspended = false; 320 } 321 return error; 322} 323 324// SetTo 325bool 326NameIndexEntryIterator::SetTo(NameIndex *index, const char *name, 327 bool ignoreValue) 328{ 329 Resume(); 330 fIndex = index; 331 fSuspended = false; 332 fIsNext = false; 333 if (fIndex) { 334 if (ignoreValue) { 335 fIndex->fEntries->GetIterator(&fIterator); 336 return fIterator.GetCurrent(); 337 } 338 return fIndex->fEntries->FindFirst(name, &fIterator); 339 } 340 return false; 341} 342 343// EntryRemoved 344void 345NameIndexEntryIterator::EntryRemoved(Entry */*entry*/) 346{ 347 Resume(); 348 fIsNext = GetNext(); 349 Suspend(); 350} 351 352