xref: /haiku/src/add-ons/kernel/file_systems/ramfs/NameIndex.cpp (revision cb29eafe2586fdb2d7685afa69fdab5d88a8b576)
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