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 16 class NameIndexPrimaryKey { 17 public: 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 29 class NameIndexGetPrimaryKey { 30 public: 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 44 class NameIndexPrimaryKeyCompare 45 { 46 public: 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 59 typedef TwoKeyAVLTree<Entry*, NameIndexPrimaryKey, NameIndexPrimaryKeyCompare, 60 NameIndexGetPrimaryKey> 61 _EntryTree; 62 63 class NameIndex::EntryTree : public _EntryTree {}; 64 65 66 // NameIndexEntryIterator 67 class NameIndexEntryIterator : public AbstractIndexEntryIterator, 68 public EntryListener { 69 public: 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 85 private: 86 friend class NameIndex; 87 88 typedef AbstractIndexEntryIterator BaseClass; 89 90 private: 91 NameIndex *fIndex; 92 NameIndex::EntryTree::Iterator fIterator; 93 bool fSuspended; 94 bool fIsNext; 95 }; 96 97 98 // NameIndex 99 100 // constructor 101 NameIndex::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 114 NameIndex::~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 127 int32 128 NameIndex::CountEntries() const 129 { 130 return fEntries->CountItems(); 131 } 132 133 // Changed 134 status_t 135 NameIndex::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 154 void 155 NameIndex::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 166 void 167 NameIndex::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 178 AbstractIndexEntryIterator * 179 NameIndex::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 192 AbstractIndexEntryIterator * 193 NameIndex::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 221 void 222 NameIndex::_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 234 NameIndexEntryIterator::NameIndexEntryIterator() 235 : AbstractIndexEntryIterator(), 236 fIndex(NULL), 237 fIterator(), 238 fSuspended(false), 239 fIsNext(false) 240 { 241 } 242 243 // destructor 244 NameIndexEntryIterator::~NameIndexEntryIterator() 245 { 246 SetTo(NULL, NULL); 247 } 248 249 // GetCurrent 250 Entry * 251 NameIndexEntryIterator::GetCurrent() 252 { 253 return (fIndex && fIterator.GetCurrent() ? *fIterator.GetCurrent() : NULL); 254 } 255 256 // GetCurrent 257 Entry * 258 NameIndexEntryIterator::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 269 Entry * 270 NameIndexEntryIterator::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 281 Entry * 282 NameIndexEntryIterator::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 293 status_t 294 NameIndexEntryIterator::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 309 status_t 310 NameIndexEntryIterator::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 325 bool 326 NameIndexEntryIterator::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 344 void 345 NameIndexEntryIterator::EntryRemoved(Entry */*entry*/) 346 { 347 Resume(); 348 fIsNext = GetNext(); 349 Suspend(); 350 } 351 352