/* * Copyright 2007, Ingo Weinhold, ingo_weinhold@gmx.de. * All rights reserved. Distributed under the terms of the MIT license. */ #include #include "DebugSupport.h" #include "Entry.h" #include "IndexImpl.h" #include "NameIndex.h" #include "ramfs.h" #include "Volume.h" // NameIndexPrimaryKey class NameIndexPrimaryKey { public: NameIndexPrimaryKey(const Entry *entry, const char *name = NULL) : entry(entry), name(name ? name : entry->GetName()) {} NameIndexPrimaryKey(const char *name) : entry(NULL), name(name) {} const Entry *entry; const char *name; }; // NameIndexGetPrimaryKey class NameIndexGetPrimaryKey { public: inline NameIndexPrimaryKey operator()(const Entry *a) { return NameIndexPrimaryKey(a); } inline NameIndexPrimaryKey operator()(const Entry *a) const { return NameIndexPrimaryKey(a); } }; // NameIndexPrimaryKeyCompare class NameIndexPrimaryKeyCompare { public: inline int operator()(const NameIndexPrimaryKey &a, const NameIndexPrimaryKey &b) const { if (a.entry != NULL && a.entry == b.entry) return 0; return strcmp(a.name, b.name); } }; // EntryTree typedef TwoKeyAVLTree _EntryTree; class NameIndex::EntryTree : public _EntryTree {}; // NameIndexEntryIterator class NameIndexEntryIterator : public AbstractIndexEntryIterator, public EntryListener { public: NameIndexEntryIterator(); virtual ~NameIndexEntryIterator(); virtual Entry *GetCurrent(); virtual Entry *GetCurrent(uint8 *buffer, size_t *keyLength); virtual Entry *GetPrevious(); virtual Entry *GetNext(); virtual status_t Suspend(); virtual status_t Resume(); bool SetTo(NameIndex *index, const char *name, bool ignoreValue = false); virtual void EntryRemoved(Entry *entry); private: friend class NameIndex; typedef AbstractIndexEntryIterator BaseClass; private: NameIndex *fIndex; NameIndex::EntryTree::Iterator fIterator; bool fSuspended; bool fIsNext; }; // NameIndex // constructor NameIndex::NameIndex(Volume *volume) : Index(volume, "name", B_STRING_TYPE, false), fEntries(new(nothrow) EntryTree) { if (fInitStatus == B_OK && !fEntries) fInitStatus = B_NO_MEMORY; if (fInitStatus == B_OK) { fInitStatus = fVolume->AddEntryListener(this, NULL, ENTRY_LISTEN_ANY_ENTRY | ENTRY_LISTEN_ALL); } } // destructor NameIndex::~NameIndex() { if (fVolume) fVolume->RemoveEntryListener(this, NULL); if (fEntries) delete fEntries; // Actually we would need to maintain a list of iterators and unset the // still existing iterators here. But since the name index is deleted // when the volume is unmounted, there shouldn't be any iterators left // anymore. } // CountEntries int32 NameIndex::CountEntries() const { return fEntries->CountItems(); } // Changed status_t NameIndex::Changed(Entry *entry, const char *oldName) { status_t error = B_BAD_VALUE; if (entry && oldName) { EntryTree::Iterator it; Entry **foundEntry = fEntries->Find(NameIndexPrimaryKey(entry, oldName), entry, &it); if (foundEntry && *foundEntry == entry) { it.Remove(); error = fEntries->Insert(entry); // udpate live queries _UpdateLiveQueries(entry, oldName, entry->GetName()); } } return error; } // EntryAdded void NameIndex::EntryAdded(Entry *entry) { if (entry) { fEntries->Insert(entry); // udpate live queries _UpdateLiveQueries(entry, NULL, entry->GetName()); } } // EntryRemoved void NameIndex::EntryRemoved(Entry *entry) { if (entry) { fEntries->Remove(entry, entry); // udpate live queries _UpdateLiveQueries(entry, entry->GetName(), NULL); } } // InternalGetIterator AbstractIndexEntryIterator * NameIndex::InternalGetIterator() { NameIndexEntryIterator *iterator = new(nothrow) NameIndexEntryIterator; if (iterator) { if (!iterator->SetTo(this, NULL, true)) { delete iterator; iterator = NULL; } } return iterator; } // InternalFind AbstractIndexEntryIterator * NameIndex::InternalFind(const uint8 *key, size_t length) { if (!key || length == 0) return NULL; // if the key is not null-terminated, copy it uint8 clonedKey[kMaxIndexKeyLength]; if (key[length - 1] != '\0') { if (length >= kMaxIndexKeyLength) length = kMaxIndexKeyLength - 1; memcpy(clonedKey, key, length); clonedKey[length] = '\0'; length++; key = clonedKey; } NameIndexEntryIterator *iterator = new(nothrow) NameIndexEntryIterator; if (iterator) { if (!iterator->SetTo(this, (const char *)key)) { delete iterator; iterator = NULL; } } return iterator; } // _UpdateLiveQueries void NameIndex::_UpdateLiveQueries(Entry* entry, const char* oldName, const char* newName) { fVolume->UpdateLiveQueries(entry, entry->GetNode(), GetName(), GetType(), (const uint8*)oldName, (oldName ? strlen(oldName) : 0), (const uint8*)newName, (newName ? strlen(newName) : 0)); } // NameIndexEntryIterator // constructor NameIndexEntryIterator::NameIndexEntryIterator() : AbstractIndexEntryIterator(), fIndex(NULL), fIterator(), fSuspended(false), fIsNext(false) { } // destructor NameIndexEntryIterator::~NameIndexEntryIterator() { SetTo(NULL, NULL); } // GetCurrent Entry * NameIndexEntryIterator::GetCurrent() { return (fIndex && fIterator.GetCurrent() ? *fIterator.GetCurrent() : NULL); } // GetCurrent Entry * NameIndexEntryIterator::GetCurrent(uint8 *buffer, size_t *keyLength) { Entry *entry = GetCurrent(); if (entry) { strncpy((char*)buffer, entry->GetName(), kMaxIndexKeyLength); *keyLength = strlen(entry->GetName()); } return entry; } // GetPrevious Entry * NameIndexEntryIterator::GetPrevious() { if (fSuspended) return NULL; if (!(fIterator.GetCurrent() && fIsNext)) fIterator.GetPrevious(); fIsNext = false; return (fIndex && fIterator.GetCurrent() ? *fIterator.GetCurrent() : NULL); } // GetNext Entry * NameIndexEntryIterator::GetNext() { if (fSuspended) return NULL; if (!(fIterator.GetCurrent() && fIsNext)) fIterator.GetNext(); fIsNext = false; return (fIndex && fIterator.GetCurrent() ? *fIterator.GetCurrent() : NULL); } // Suspend status_t NameIndexEntryIterator::Suspend() { status_t error = (!fSuspended ? B_OK : B_BAD_VALUE); if (error == B_OK) { if (fIterator.GetCurrent()) { error = fIndex->GetVolume()->AddEntryListener(this, *fIterator.GetCurrent(), ENTRY_LISTEN_REMOVED); } if (error == B_OK) fSuspended = true; } return error; } // Resume status_t NameIndexEntryIterator::Resume() { status_t error = (fSuspended ? B_OK : B_BAD_VALUE); if (error == B_OK) { if (fIterator.GetCurrent()) { error = fIndex->GetVolume()->RemoveEntryListener(this, *fIterator.GetCurrent()); } if (error == B_OK) fSuspended = false; } return error; } // SetTo bool NameIndexEntryIterator::SetTo(NameIndex *index, const char *name, bool ignoreValue) { Resume(); fIndex = index; fSuspended = false; fIsNext = false; if (fIndex) { if (ignoreValue) { fIndex->fEntries->GetIterator(&fIterator); return fIterator.GetCurrent(); } return fIndex->fEntries->FindFirst(name, &fIterator); } return false; } // EntryRemoved void NameIndexEntryIterator::EntryRemoved(Entry */*entry*/) { Resume(); fIsNext = GetNext(); Suspend(); }