xref: /haiku/src/add-ons/kernel/file_systems/ramfs/Query.cpp (revision e1c4049fed1047bdb957b0529e1921e97ef94770)
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 
108 	struct Index {
109 		Query*		query;
110 		::Index*	index;
111 
112 		Index(Context* context)
113 			:
114 			query(context)
115 		{
116 		}
117 	};
118 
119 	struct IndexIterator : ::IndexIterator {
120 		IndexIterator(::Index* index)
121 			:
122 			::IndexIterator(index)
123 		{
124 		}
125 	};
126 
127 	static const int32 kMaxFileNameLength = B_FILE_NAME_LENGTH;
128 
129 	// Entry interface
130 
131 	static ino_t EntryGetParentID(Entry* entry)
132 	{
133 		return entry->GetParent()->GetID();
134 	}
135 
136 	static Node* EntryGetNode(Entry* entry)
137 	{
138 		return entry->GetNode();
139 	}
140 
141 	static ino_t EntryGetNodeID(Entry* entry)
142 	{
143 		return entry->GetNode()->GetID();
144 	}
145 
146 	static ssize_t EntryGetName(Entry* entry, void* buffer, size_t bufferSize)
147 	{
148 		const char* name = entry->GetName();
149 		size_t nameLength = strlen(name);
150 		if (nameLength >= bufferSize)
151 			return B_BUFFER_OVERFLOW;
152 
153 		memcpy(buffer, name, nameLength + 1);
154 		return nameLength + 1;
155 	}
156 
157 	static const char* EntryGetNameNoCopy(Entry* entry, void* buffer,
158 		size_t bufferSize)
159 	{
160 		return entry->GetName();
161 	}
162 
163 	// Index interface
164 
165 	static status_t IndexSetTo(Index& index, const char* attribute)
166 	{
167 		index.index = index.query->fVolume->FindIndex(attribute);
168 		return index.index != NULL ? B_OK : B_ENTRY_NOT_FOUND;
169 	}
170 
171 	static void IndexUnset(Index& index)
172 	{
173 		index.index = NULL;
174 	}
175 
176 	static int32 IndexGetWeightedScore(Index& index, int32 score)
177 	{
178 		// should be inversely proportional to the index size; max input score
179 		// is 2048
180 		static const int32 maxFactor = (1024 * 1024) - 1;
181 		return score * (maxFactor /
182 			std::min(maxFactor, std::max((int32)1, index.index->CountEntries())));
183 	}
184 
185 	static type_code IndexGetType(Index& index)
186 	{
187 		return index.index->GetType();
188 	}
189 
190 	static int32 IndexGetKeySize(Index& index)
191 	{
192 		return index.index->GetKeyLength();
193 	}
194 
195 	static IndexIterator* IndexCreateIterator(Index& index)
196 	{
197 		IndexIterator* iterator = new(std::nothrow) IndexIterator(index.index);
198 		if (iterator == NULL)
199 			return NULL;
200 
201 		return iterator;
202 	}
203 
204 	// IndexIterator interface
205 
206 	static void IndexIteratorDelete(IndexIterator* indexIterator)
207 	{
208 		delete indexIterator;
209 	}
210 
211 	static status_t IndexIteratorFind(IndexIterator* indexIterator,
212 		const void* value, size_t size)
213 	{
214 		return indexIterator->Find((const uint8*)value, size);
215 	}
216 
217 	static status_t IndexIteratorGetNextEntry(IndexIterator* indexIterator,
218 		void* value, size_t* _valueLength, size_t bufferSize, Entry** _entry)
219 	{
220 		return indexIterator->GetNextEntry((uint8*)value, _valueLength, _entry);
221 	}
222 
223 	static void IndexIteratorSuspend(IndexIterator* indexIterator)
224 	{
225 		// Nothing to do.
226 	}
227 
228 	static void IndexIteratorResume(IndexIterator* indexIterator)
229 	{
230 		// Nothing to do.
231 	}
232 
233 	// Node interface
234 
235 	static const off_t NodeGetSize(Node* node)
236 	{
237 		return node->GetSize();
238 	}
239 
240 	static time_t NodeGetLastModifiedTime(Node* node)
241 	{
242 		return node->GetMTime();
243 	}
244 
245 	static status_t NodeGetAttribute(Node* node, const char* attribute,
246 		void* buffer, size_t* _size, int32* _type)
247 	{
248 		Attribute* attr = NULL;
249 		status_t error = node->FindAttribute(attribute, &attr);
250 		if (error != B_OK)
251 			return error;
252 
253 		*_type = attr->GetType();
254 		error = attr->ReadAt(0, buffer, *_size, _size);
255 
256 		return error;
257 	}
258 
259 	static Entry* NodeGetFirstReferrer(Node* node)
260 	{
261 		return node->GetFirstReferrer();
262 	}
263 
264 	static Entry* NodeGetNextReferrer(Node* node, Entry* entry)
265 	{
266 		return node->GetNextReferrer(entry);
267 	}
268 
269 	// Volume interface
270 
271 	static dev_t ContextGetVolumeID(Context* context)
272 	{
273 		return context->fVolume->GetID();
274 	}
275 };
276 
277 
278 // #pragma mark - Query
279 
280 
281 Query::Query(Volume* volume)
282 	:
283 	fVolume(volume),
284 	fImpl(NULL)
285 {
286 }
287 
288 
289 Query::~Query()
290 {
291 	if (fImpl != NULL) {
292 		if ((fImpl->Flags() & B_LIVE_QUERY) != 0)
293 			fVolume->RemoveQuery(this);
294 
295 		delete fImpl;
296 	}
297 }
298 
299 
300 /*static*/ status_t
301 Query::Create(Volume* volume, const char* queryString, uint32 flags,
302 	port_id port, uint32 token, Query*& _query)
303 {
304 	Query* query = new(std::nothrow) Query(volume);
305 	if (query == NULL)
306 		return B_NO_MEMORY;
307 
308 	status_t error = query->_Init(queryString, flags, port, token);
309 	if (error != B_OK) {
310 		delete query;
311 		return error;
312 	}
313 
314 	_query = query;
315 	return B_OK;
316 }
317 
318 
319 status_t
320 Query::Rewind()
321 {
322 	return fImpl->Rewind();
323 }
324 
325 
326 status_t
327 Query::GetNextEntry(struct dirent* entry, size_t size)
328 {
329 	return fImpl->GetNextEntry(entry, size);
330 }
331 
332 
333 void
334 Query::LiveUpdate(Entry* entry, Node* node, const char* attribute, int32 type,
335 	const void* oldKey, size_t oldLength, const void* newKey, size_t newLength)
336 {
337 	fImpl->LiveUpdate(entry, node, attribute, type, (const uint8*)oldKey,
338 		oldLength, (const uint8*)newKey, newLength);
339 }
340 
341 
342 status_t
343 Query::_Init(const char* queryString, uint32 flags, port_id port, uint32 token)
344 {
345 	status_t error = QueryImpl::Create(this, queryString, flags, port, token,
346 		fImpl);
347 	if (error != B_OK)
348 		return error;
349 
350 	if ((fImpl->Flags() & B_LIVE_QUERY) != 0)
351 		fVolume->AddQuery(this);
352 
353 	return B_OK;
354 }
355