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