1/*
2 * Copyright 2002-2009, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Tyler Dauwalder
7 *		Ingo Weinhold
8 *		Axel D��rfler, axeld@pinc-software.de.
9 */
10
11
12#include <Query.h>
13
14#include <fcntl.h>
15#include <new>
16#include <time.h>
17
18#include <Entry.h>
19#include <fs_query.h>
20#include <parsedate.h>
21#include <Volume.h>
22
23#include <MessengerPrivate.h>
24#include <syscalls.h>
25#include <query_private.h>
26
27#include "QueryPredicate.h"
28#include "storage_support.h"
29
30
31using namespace std;
32using namespace BPrivate::Storage;
33
34
35// Creates an uninitialized BQuery.
36BQuery::BQuery()
37	:
38	BEntryList(),
39	fStack(NULL),
40	fPredicate(NULL),
41	fDevice((dev_t)B_ERROR),
42	fLive(false),
43	fPort(B_ERROR),
44	fToken(0),
45	fQueryFd(-1)
46{
47}
48
49
50// Frees all resources associated with the object.
51BQuery::~BQuery()
52{
53	Clear();
54}
55
56
57// Resets the object to a uninitialized state.
58status_t
59BQuery::Clear()
60{
61	// close the currently open query
62	status_t error = B_OK;
63	if (fQueryFd >= 0) {
64		error = _kern_close(fQueryFd);
65		fQueryFd = -1;
66	}
67	// delete the predicate stack and the predicate
68	delete fStack;
69	fStack = NULL;
70	delete[] fPredicate;
71	fPredicate = NULL;
72	// reset the other parameters
73	fDevice = (dev_t)B_ERROR;
74	fLive = false;
75	fPort = B_ERROR;
76	fToken = 0;
77	return error;
78}
79
80
81// Pushes an attribute name onto the predicate stack.
82status_t
83BQuery::PushAttr(const char* attrName)
84{
85	return _PushNode(new(nothrow) AttributeNode(attrName), true);
86}
87
88
89// Pushes an operator onto the predicate stack.
90status_t
91BQuery::PushOp(query_op op)
92{
93	status_t error = B_OK;
94	switch (op) {
95		case B_EQ:
96		case B_GT:
97		case B_GE:
98		case B_LT:
99		case B_LE:
100		case B_NE:
101		case B_CONTAINS:
102		case B_BEGINS_WITH:
103		case B_ENDS_WITH:
104		case B_AND:
105		case B_OR:
106			error = _PushNode(new(nothrow) BinaryOpNode(op), true);
107			break;
108		case B_NOT:
109			error = _PushNode(new(nothrow) UnaryOpNode(op), true);
110			break;
111		default:
112			error = _PushNode(new(nothrow) SpecialOpNode(op), true);
113			break;
114	}
115	return error;
116}
117
118
119// Pushes a uint32 onto the predicate stack.
120status_t
121BQuery::PushUInt32(uint32 value)
122{
123	return _PushNode(new(nothrow) UInt32ValueNode(value), true);
124}
125
126
127// Pushes an int32 onto the predicate stack.
128status_t
129BQuery::PushInt32(int32 value)
130{
131	return _PushNode(new(nothrow) Int32ValueNode(value), true);
132}
133
134
135// Pushes a uint64 onto the predicate stack.
136status_t
137BQuery::PushUInt64(uint64 value)
138{
139	return _PushNode(new(nothrow) UInt64ValueNode(value), true);
140}
141
142
143// Pushes an int64 onto the predicate stack.
144status_t
145BQuery::PushInt64(int64 value)
146{
147	return _PushNode(new(nothrow) Int64ValueNode(value), true);
148}
149
150
151// Pushes a float onto the predicate stack.
152status_t
153BQuery::PushFloat(float value)
154{
155	return _PushNode(new(nothrow) FloatValueNode(value), true);
156}
157
158
159// Pushes a double onto the predicate stack.
160status_t
161BQuery::PushDouble(double value)
162{
163	return _PushNode(new(nothrow) DoubleValueNode(value), true);
164}
165
166
167// Pushes a string onto the predicate stack.
168status_t
169BQuery::PushString(const char* value, bool caseInsensitive)
170{
171	return _PushNode(new(nothrow) StringNode(value, caseInsensitive), true);
172}
173
174
175// Pushes a date onto the predicate stack.
176status_t
177BQuery::PushDate(const char* date)
178{
179	if (date == NULL || !date[0] || parsedate(date, time(NULL)) < 0)
180		return B_BAD_VALUE;
181
182	return _PushNode(new(nothrow) DateNode(date), true);
183}
184
185
186// Assigns a volume to the BQuery object.
187status_t
188BQuery::SetVolume(const BVolume* volume)
189{
190	if (volume == NULL)
191		return B_BAD_VALUE;
192	if (_HasFetched())
193		return B_NOT_ALLOWED;
194
195	if (volume->InitCheck() == B_OK)
196		fDevice = volume->Device();
197	else
198		fDevice = (dev_t)B_ERROR;
199
200	return B_OK;
201}
202
203
204// Assigns the passed-in predicate expression.
205status_t
206BQuery::SetPredicate(const char* expression)
207{
208	status_t error = (expression ? B_OK : B_BAD_VALUE);
209	if (error == B_OK && _HasFetched())
210		error = B_NOT_ALLOWED;
211	if (error == B_OK)
212		error = _SetPredicate(expression);
213	return error;
214}
215
216
217// Assigns the target messenger and makes the query live.
218status_t
219BQuery::SetTarget(BMessenger messenger)
220{
221	status_t error = (messenger.IsValid() ? B_OK : B_BAD_VALUE);
222	if (error == B_OK && _HasFetched())
223		error = B_NOT_ALLOWED;
224	if (error == B_OK) {
225		BMessenger::Private messengerPrivate(messenger);
226		fPort = messengerPrivate.Port();
227		fToken = (messengerPrivate.IsPreferredTarget()
228			? -1 : messengerPrivate.Token());
229		fLive = true;
230	}
231	return error;
232}
233
234
235// Gets whether the query associated with this object is live.
236bool
237BQuery::IsLive() const
238{
239	return fLive;
240}
241
242
243// Fills out buffer with the predicate string assigned to the BQuery object.
244status_t
245BQuery::GetPredicate(char* buffer, size_t length)
246{
247	status_t error = (buffer ? B_OK : B_BAD_VALUE);
248	if (error == B_OK)
249		_EvaluateStack();
250	if (error == B_OK && !fPredicate)
251		error = B_NO_INIT;
252	if (error == B_OK && length <= strlen(fPredicate))
253		error = B_BAD_VALUE;
254	if (error == B_OK)
255		strcpy(buffer, fPredicate);
256	return error;
257}
258
259
260// Fills out the passed-in BString object with the predicate string
261// assigned to the BQuery object.
262status_t
263BQuery::GetPredicate(BString* predicate)
264{
265	status_t error = (predicate ? B_OK : B_BAD_VALUE);
266	if (error == B_OK)
267		_EvaluateStack();
268	if (error == B_OK && !fPredicate)
269		error = B_NO_INIT;
270	if (error == B_OK)
271		predicate->SetTo(fPredicate);
272	return error;
273}
274
275
276// Gets the length of the predicate string.
277size_t
278BQuery::PredicateLength()
279{
280	status_t error = _EvaluateStack();
281	if (error == B_OK && !fPredicate)
282		error = B_NO_INIT;
283	size_t size = 0;
284	if (error == B_OK)
285		size = strlen(fPredicate) + 1;
286	return size;
287}
288
289
290// Gets the device ID identifying the volume of the BQuery object.
291dev_t
292BQuery::TargetDevice() const
293{
294	return fDevice;
295}
296
297
298// Start fetching entries satisfying the predicate.
299status_t
300BQuery::Fetch()
301{
302	if (_HasFetched())
303		return B_NOT_ALLOWED;
304
305	_EvaluateStack();
306
307	if (!fPredicate || fDevice < 0)
308		return B_NO_INIT;
309
310	BString parsedPredicate;
311	_ParseDates(parsedPredicate);
312
313	fQueryFd = _kern_open_query(fDevice, parsedPredicate.String(),
314		parsedPredicate.Length(), fLive ? B_LIVE_QUERY : 0, fPort, fToken);
315	if (fQueryFd < 0)
316		return fQueryFd;
317
318	// set close on exec flag
319	fcntl(fQueryFd, F_SETFD, FD_CLOEXEC);
320
321	return B_OK;
322}
323
324
325//	#pragma mark - BEntryList interface
326
327
328// Fills out entry with the next entry traversing symlinks if traverse is true.
329status_t
330BQuery::GetNextEntry(BEntry* entry, bool traverse)
331{
332	status_t error = (entry ? B_OK : B_BAD_VALUE);
333	if (error == B_OK) {
334		entry_ref ref;
335		error = GetNextRef(&ref);
336		if (error == B_OK)
337			error = entry->SetTo(&ref, traverse);
338	}
339	return error;
340}
341
342
343// Fills out ref with the next entry as an entry_ref.
344status_t
345BQuery::GetNextRef(entry_ref* ref)
346{
347	status_t error = (ref ? B_OK : B_BAD_VALUE);
348	if (error == B_OK && !_HasFetched())
349		error = B_FILE_ERROR;
350	if (error == B_OK) {
351		BPrivate::Storage::LongDirEntry longEntry;
352		struct dirent* entry = longEntry.dirent();
353		bool next = true;
354		while (error == B_OK && next) {
355			if (GetNextDirents(entry, sizeof(longEntry), 1) != 1) {
356				error = B_ENTRY_NOT_FOUND;
357			} else {
358				next = (!strcmp(entry->d_name, ".")
359						|| !strcmp(entry->d_name, ".."));
360			}
361		}
362		if (error == B_OK) {
363			ref->device = entry->d_pdev;
364			ref->directory = entry->d_pino;
365			error = ref->set_name(entry->d_name);
366		}
367	}
368	return error;
369}
370
371
372// Fill out up to count entries into the array of dirent structs pointed
373// to by buffer.
374int32
375BQuery::GetNextDirents(struct dirent* buffer, size_t length, int32 count)
376{
377	if (!buffer)
378		return B_BAD_VALUE;
379	if (!_HasFetched())
380		return B_FILE_ERROR;
381	return _kern_read_dir(fQueryFd, buffer, length, count);
382}
383
384
385// Rewinds the entry list back to the first entry.
386status_t
387BQuery::Rewind()
388{
389	if (!_HasFetched())
390		return B_FILE_ERROR;
391	return _kern_rewind_dir(fQueryFd);
392}
393
394
395// Unimplemented method of the BEntryList interface.
396int32
397BQuery::CountEntries()
398{
399	return B_ERROR;
400}
401
402
403/*!	Gets whether Fetch() has already been called on this object.
404
405	\return \c true, if Fetch() was already called, \c false otherwise.
406*/
407bool
408BQuery::_HasFetched() const
409{
410	return fQueryFd >= 0;
411}
412
413
414/*!	Pushes a node onto the predicate stack.
415
416	If the stack has not been allocate until this time, this method does
417	allocate it.
418
419	If the supplied node is \c NULL, it is assumed that there was not enough
420	memory to allocate the node and thus \c B_NO_MEMORY is returned.
421
422	In case the method fails, the caller retains the ownership of the supplied
423	node and thus is responsible for deleting it, if \a deleteOnError is
424	\c false. If it is \c true, the node is deleted, if an error occurs.
425
426	\param node The node to push.
427	\param deleteOnError Whether or not to delete the node if an error occurs.
428
429	\return A status code.
430	\retval B_OK Everything went fine.
431	\retval B_NO_MEMORY \a node was \c NULL or there was insufficient memory to
432	        allocate the predicate stack or push the node.
433	\retval B_NOT_ALLOWED _PushNode() was called after Fetch().
434*/
435status_t
436BQuery::_PushNode(QueryNode* node, bool deleteOnError)
437{
438	status_t error = (node ? B_OK : B_NO_MEMORY);
439	if (error == B_OK && _HasFetched())
440		error = B_NOT_ALLOWED;
441	// allocate the stack, if necessary
442	if (error == B_OK && !fStack) {
443		fStack = new(nothrow) QueryStack;
444		if (!fStack)
445			error = B_NO_MEMORY;
446	}
447	if (error == B_OK)
448		error = fStack->PushNode(node);
449	if (error != B_OK && deleteOnError)
450		delete node;
451	return error;
452}
453
454
455/*!	Helper method to set the predicate.
456
457	Does not check whether Fetch() has already been invoked.
458
459	\param expression The predicate string to set.
460
461	\return A status code.
462	\retval B_OK Everything went fine.
463	\retval B_NO_MEMORY There was insufficient memory to store the predicate.
464*/
465status_t
466BQuery::_SetPredicate(const char* expression)
467{
468	status_t error = B_OK;
469	// unset the old predicate
470	delete[] fPredicate;
471	fPredicate = NULL;
472	// set the new one
473	if (expression) {
474		fPredicate = new(nothrow) char[strlen(expression) + 1];
475		if (fPredicate)
476			strcpy(fPredicate, expression);
477		else
478			error = B_NO_MEMORY;
479	}
480	return error;
481}
482
483
484/*!	Evaluates the predicate stack.
485
486	The method does nothing (and returns \c B_OK), if the stack is \c NULL.
487	If the stack is not  \c null and Fetch() has already been called, this
488	method fails.
489
490	\return A status code.
491	\retval B_OK Everything went fine.
492	\retval B_NO_MEMORY There was insufficient memory.
493	\retval B_NOT_ALLOWED _EvaluateStack() was called after Fetch().
494*/
495status_t
496BQuery::_EvaluateStack()
497{
498	status_t error = B_OK;
499	if (fStack) {
500		_SetPredicate(NULL);
501		if (_HasFetched())
502			error = B_NOT_ALLOWED;
503		// convert the stack to a tree and evaluate it
504		QueryNode* node = NULL;
505		if (error == B_OK)
506			error = fStack->ConvertToTree(node);
507		BString predicate;
508		if (error == B_OK)
509			error = node->GetString(predicate);
510		if (error == B_OK)
511			error = _SetPredicate(predicate.String());
512		delete fStack;
513		fStack = NULL;
514	}
515	return error;
516}
517
518
519/*!	Fills out \a parsedPredicate with a parsed predicate string.
520
521	\param parsedPredicate The predicate string to fill out.
522*/
523void
524BQuery::_ParseDates(BString& parsedPredicate)
525{
526	const char* start = fPredicate;
527	const char* pos = start;
528	bool quotes = false;
529
530	while (pos[0]) {
531		if (pos[0] == '\\') {
532			pos++;
533			continue;
534		}
535		if (pos[0] == '"')
536			quotes = !quotes;
537		else if (!quotes && pos[0] == '%') {
538			const char* end = strchr(pos + 1, '%');
539			if (end == NULL)
540				continue;
541
542			parsedPredicate.Append(start, pos - start);
543			start = end + 1;
544
545			// We have a date string
546			BString date(pos + 1, start - 1 - pos);
547			parsedPredicate << parsedate(date.String(), time(NULL));
548
549			pos = end;
550		}
551		pos++;
552	}
553
554	parsedPredicate.Append(start, pos - start);
555}
556
557
558// FBC
559void BQuery::_QwertyQuery1() {}
560void BQuery::_QwertyQuery2() {}
561void BQuery::_QwertyQuery3() {}
562void BQuery::_QwertyQuery4() {}
563void BQuery::_QwertyQuery5() {}
564void BQuery::_QwertyQuery6() {}
565
566