xref: /haiku/src/add-ons/kernel/file_systems/ramfs/Query.cpp (revision b8a45b3a2df2379b4301bf3bd5949b9a105be4ba)
1 /*
2  * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Copyright 2023, Haiku, Inc. All rights reserved.
4  * Distributed under the terms of the MIT License.
5  */
6 
7 #include "Query.h"
8 
9 #include "Directory.h"
10 #include "Entry.h"
11 #include "Node.h"
12 #include "Volume.h"
13 #include "Index.h"
14 
15 #include <file_systems/QueryParser.h>
16 
17 
18 // #pragma mark - IndexIterator
19 
20 
21 class IndexIterator {
22 public:
23 	IndexIterator(Index *index);
24 
25 	status_t Find(const uint8 *const key, size_t keyLength);
26 	status_t Rewind();
27 	status_t GetNextEntry(uint8 *buffer, size_t *keyLength, Entry **entry);
28 
29 	Index* GetIndex() const { return fIndex; }
30 
31 private:
32 	Index				*fIndex;
33 	IndexEntryIterator	fIterator;
34 	bool				fInitialized;
35 };
36 
37 
38 IndexIterator::IndexIterator(Index *index)
39 	: fIndex(index),
40 	  fIterator(),
41 	  fInitialized(false)
42 {
43 }
44 
45 
46 status_t
47 IndexIterator::Find(const uint8 *const key, size_t keyLength)
48 {
49 	status_t error = B_ENTRY_NOT_FOUND;
50 	if (fIndex) {
51 		// TODO: We actually don't want an exact Find() here, but rather a
52 		// FindClose().
53 		fInitialized = fIndex->Find(key, keyLength, &fIterator);
54 		if (fInitialized)
55 			error = B_OK;
56 	}
57 	return error;
58 }
59 
60 
61 status_t
62 IndexIterator::Rewind()
63 {
64 	status_t error = B_ENTRY_NOT_FOUND;
65 	if (fIndex) {
66 		fInitialized = fIndex->GetIterator(&fIterator);
67 		if (fInitialized)
68 			error = B_OK;
69 	}
70 	return error;
71 }
72 
73 
74 status_t
75 IndexIterator::GetNextEntry(uint8 *buffer, size_t *_keyLength, Entry **_entry)
76 {
77 	status_t error = B_ENTRY_NOT_FOUND;
78 	if (fIndex) {
79 		// init iterator, if not done yet
80 		if (!fInitialized) {
81 			fIndex->GetIterator(&fIterator);
82 			fInitialized = true;
83 		}
84 
85 		// get key
86 		size_t keyLength;
87 		if (Entry *entry = fIterator.GetCurrent(buffer, &keyLength)) {
88 			*_keyLength = keyLength;
89 			*_entry = entry;
90 			error = B_OK;
91 		}
92 
93 		// get next entry
94 		fIterator.GetNext();
95 	}
96 	return error;
97 }
98 
99 
100 // #pragma mark - QueryPolicy
101 
102 
103 struct Query::QueryPolicy {
104 	typedef Query Context;
105 	typedef ::Entry Entry;
106 	typedef ::Node Node;
107 	typedef void* NodeHolder;
108 
109 	struct Index {
110 		Query*		query;
111 		::Index*	index;
112 
113 		Index(Context* context)
114 			:
115 			query(context)
116 		{
117 		}
118 	};
119 
120 	struct IndexIterator : ::IndexIterator {
121 		Entry* entry;
122 
123 		IndexIterator(::Index* index)
124 			:
125 			::IndexIterator(index)
126 		{
127 		}
128 	};
129 
130 	static const int32 kMaxFileNameLength = B_FILE_NAME_LENGTH;
131 
132 	// Entry interface
133 
134 	static ino_t EntryGetParentID(Entry* entry)
135 	{
136 		return entry->GetParent()->GetID();
137 	}
138 
139 	static Node* EntryGetNode(Entry* entry)
140 	{
141 		return entry->GetNode();
142 	}
143 
144 	static ino_t EntryGetNodeID(Entry* entry)
145 	{
146 		return entry->GetNode()->GetID();
147 	}
148 
149 	static ssize_t EntryGetName(Entry* entry, void* buffer, size_t bufferSize)
150 	{
151 		const char* name = entry->GetName();
152 		size_t nameLength = strlen(name);
153 		if (nameLength >= bufferSize)
154 			return B_BUFFER_OVERFLOW;
155 
156 		memcpy(buffer, name, nameLength + 1);
157 		return nameLength + 1;
158 	}
159 
160 	static const char* EntryGetNameNoCopy(NodeHolder& holder, Entry* entry)
161 	{
162 		return entry->GetName();
163 	}
164 
165 	// Index interface
166 
167 	static status_t IndexSetTo(Index& index, const char* attribute)
168 	{
169 		index.index = index.query->fVolume->FindIndex(attribute);
170 		return index.index != NULL ? B_OK : B_ENTRY_NOT_FOUND;
171 	}
172 
173 	static void IndexUnset(Index& index)
174 	{
175 		index.index = NULL;
176 	}
177 
178 	static int32 IndexGetWeightedScore(Index& index, int32 score)
179 	{
180 		// should be inversely proportional to the index size; max input score
181 		// is 2048
182 		static const int32 maxFactor = (1024 * 1024) - 1;
183 		return score * (maxFactor /
184 			std::min(maxFactor, std::max((int32)1, index.index->CountEntries())));
185 	}
186 
187 	static type_code IndexGetType(Index& index)
188 	{
189 		return index.index->GetType();
190 	}
191 
192 	static int32 IndexGetKeySize(Index& index)
193 	{
194 		return index.index->GetKeyLength();
195 	}
196 
197 	static IndexIterator* IndexCreateIterator(Index& index)
198 	{
199 		IndexIterator* iterator = new(std::nothrow) IndexIterator(index.index);
200 		if (iterator == NULL)
201 			return NULL;
202 
203 		return iterator;
204 	}
205 
206 	// IndexIterator interface
207 
208 	static void IndexIteratorDelete(IndexIterator* indexIterator)
209 	{
210 		delete indexIterator;
211 	}
212 
213 	static status_t IndexIteratorFind(IndexIterator* indexIterator,
214 		const void* value, size_t size)
215 	{
216 		return indexIterator->Find((const uint8*)value, size);
217 	}
218 
219 	static status_t IndexIteratorFetchNextEntry(IndexIterator* indexIterator,
220 		void* value, size_t* _valueLength, size_t bufferSize, size_t* duplicate)
221 	{
222 		return indexIterator->GetNextEntry((uint8*)value, _valueLength, &indexIterator->entry);
223 	}
224 
225 	static status_t IndexIteratorGetEntry(Context* context, IndexIterator* indexIterator,
226 		NodeHolder& holder, Entry** _entry)
227 	{
228 		*_entry = indexIterator->entry;
229 		return B_OK;
230 	}
231 
232 	static void IndexIteratorSkipDuplicates(IndexIterator* indexIterator)
233 	{
234 		// Nothing to do.
235 	}
236 
237 	static void IndexIteratorSuspend(IndexIterator* indexIterator)
238 	{
239 		// Nothing to do.
240 	}
241 
242 	static void IndexIteratorResume(IndexIterator* indexIterator)
243 	{
244 		// Nothing to do.
245 	}
246 
247 	// Node interface
248 
249 	static const off_t NodeGetSize(Node* node)
250 	{
251 		return node->GetSize();
252 	}
253 
254 	static time_t NodeGetLastModifiedTime(Node* node)
255 	{
256 		return node->GetMTime();
257 	}
258 
259 	static status_t NodeGetAttribute(NodeHolder& nodeHolder, Node* node,
260 		const char* attribute, void* buffer, size_t* _size, int32* _type)
261 	{
262 		Attribute* attr = NULL;
263 		status_t error = node->FindAttribute(attribute, &attr);
264 		if (error != B_OK)
265 			return error;
266 
267 		*_type = attr->GetType();
268 		error = attr->ReadAt(0, buffer, *_size, _size);
269 
270 		return error;
271 	}
272 
273 	static Entry* NodeGetFirstReferrer(Node* node)
274 	{
275 		return node->GetFirstReferrer();
276 	}
277 
278 	static Entry* NodeGetNextReferrer(Node* node, Entry* entry)
279 	{
280 		return node->GetNextReferrer(entry);
281 	}
282 
283 	// Volume interface
284 
285 	static dev_t ContextGetVolumeID(Context* context)
286 	{
287 		return context->fVolume->GetID();
288 	}
289 };
290 
291 
292 // #pragma mark - Query
293 
294 
295 Query::Query(Volume* volume)
296 	:
297 	fVolume(volume),
298 	fImpl(NULL)
299 {
300 }
301 
302 
303 Query::~Query()
304 {
305 	if (fImpl != NULL) {
306 		if ((fImpl->Flags() & B_LIVE_QUERY) != 0)
307 			fVolume->RemoveQuery(this);
308 
309 		delete fImpl;
310 	}
311 }
312 
313 
314 /*static*/ status_t
315 Query::Create(Volume* volume, const char* queryString, uint32 flags,
316 	port_id port, uint32 token, Query*& _query)
317 {
318 	Query* query = new(std::nothrow) Query(volume);
319 	if (query == NULL)
320 		return B_NO_MEMORY;
321 
322 	status_t error = query->_Init(queryString, flags, port, token);
323 	if (error != B_OK) {
324 		delete query;
325 		return error;
326 	}
327 
328 	_query = query;
329 	return B_OK;
330 }
331 
332 
333 status_t
334 Query::Rewind()
335 {
336 	return fImpl->Rewind();
337 }
338 
339 
340 status_t
341 Query::GetNextEntry(struct dirent* entry, size_t size)
342 {
343 	return fImpl->GetNextEntry(entry, size);
344 }
345 
346 
347 void
348 Query::LiveUpdate(Entry* entry, Node* node, const char* attribute, int32 type,
349 	const void* oldKey, size_t oldLength, const void* newKey, size_t newLength)
350 {
351 	fImpl->LiveUpdate(entry, node, attribute, type, (const uint8*)oldKey,
352 		oldLength, (const uint8*)newKey, newLength);
353 }
354 
355 
356 status_t
357 Query::_Init(const char* queryString, uint32 flags, port_id port, uint32 token)
358 {
359 	status_t error = QueryImpl::Create(this, queryString, flags, port, token,
360 		fImpl);
361 	if (error != B_OK)
362 		return error;
363 
364 	if ((fImpl->Flags() & B_LIVE_QUERY) != 0)
365 		fVolume->AddQuery(this);
366 
367 	return B_OK;
368 }
369