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