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
13class NameIndexPrimaryKey {
14public:
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
26class NameIndexGetPrimaryKey {
27public:
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
41class NameIndexPrimaryKeyCompare
42{
43public:
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
56typedef TwoKeyAVLTree<Entry*, NameIndexPrimaryKey, NameIndexPrimaryKeyCompare,
57					  NameIndexGetPrimaryKey>
58		_EntryTree;
59
60class NameIndex::EntryTree : public _EntryTree {};
61
62
63// NameIndexEntryIterator
64class NameIndexEntryIterator : public AbstractIndexEntryIterator,
65	public EntryListener {
66public:
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
82private:
83	friend class NameIndex;
84
85	typedef AbstractIndexEntryIterator BaseClass;
86
87private:
88	NameIndex						*fIndex;
89	NameIndex::EntryTree::Iterator	fIterator;
90	bool							fSuspended;
91	bool							fIsNext;
92};
93
94
95// NameIndex
96
97// constructor
98NameIndex::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
111NameIndex::~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
124int32
125NameIndex::CountEntries() const
126{
127	return fEntries->CountItems();
128}
129
130// Changed
131status_t
132NameIndex::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			fEntries->Remove(it);
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
151void
152NameIndex::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
163void
164NameIndex::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
175AbstractIndexEntryIterator *
176NameIndex::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
189AbstractIndexEntryIterator *
190NameIndex::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
218void
219NameIndex::_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
231NameIndexEntryIterator::NameIndexEntryIterator()
232	: AbstractIndexEntryIterator(),
233	  fIndex(NULL),
234	  fIterator(),
235	  fSuspended(false),
236	  fIsNext(false)
237{
238}
239
240// destructor
241NameIndexEntryIterator::~NameIndexEntryIterator()
242{
243	SetTo(NULL, NULL);
244}
245
246// GetCurrent
247Entry *
248NameIndexEntryIterator::GetCurrent()
249{
250	return (fIndex && fIterator.GetCurrent() ? *fIterator.GetCurrent() : NULL);
251}
252
253// GetCurrent
254Entry *
255NameIndexEntryIterator::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
266Entry *
267NameIndexEntryIterator::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
278Entry *
279NameIndexEntryIterator::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
290status_t
291NameIndexEntryIterator::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
306status_t
307NameIndexEntryIterator::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
322bool
323NameIndexEntryIterator::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
341void
342NameIndexEntryIterator::EntryRemoved(Entry */*entry*/)
343{
344	Resume();
345	fIsNext = GetNext();
346	Suspend();
347}
348
349