xref: /haiku/src/kits/storage/Query.cpp (revision bb83316a5811a550c4f850d07fa8e328e7ac0a94)
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  
31  using namespace std;
32  using namespace BPrivate::Storage;
33  
34  
35  // Creates an uninitialized BQuery.
36  BQuery::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.
51  BQuery::~BQuery()
52  {
53  	Clear();
54  }
55  
56  
57  // Resets the object to a uninitialized state.
58  status_t
59  BQuery::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.
82  status_t
83  BQuery::PushAttr(const char* attrName)
84  {
85  	return _PushNode(new(nothrow) AttributeNode(attrName), true);
86  }
87  
88  
89  // Pushes an operator onto the predicate stack.
90  status_t
91  BQuery::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.
120  status_t
121  BQuery::PushUInt32(uint32 value)
122  {
123  	return _PushNode(new(nothrow) UInt32ValueNode(value), true);
124  }
125  
126  
127  // Pushes an int32 onto the predicate stack.
128  status_t
129  BQuery::PushInt32(int32 value)
130  {
131  	return _PushNode(new(nothrow) Int32ValueNode(value), true);
132  }
133  
134  
135  // Pushes a uint64 onto the predicate stack.
136  status_t
137  BQuery::PushUInt64(uint64 value)
138  {
139  	return _PushNode(new(nothrow) UInt64ValueNode(value), true);
140  }
141  
142  
143  // Pushes an int64 onto the predicate stack.
144  status_t
145  BQuery::PushInt64(int64 value)
146  {
147  	return _PushNode(new(nothrow) Int64ValueNode(value), true);
148  }
149  
150  
151  // Pushes a float onto the predicate stack.
152  status_t
153  BQuery::PushFloat(float value)
154  {
155  	return _PushNode(new(nothrow) FloatValueNode(value), true);
156  }
157  
158  
159  // Pushes a double onto the predicate stack.
160  status_t
161  BQuery::PushDouble(double value)
162  {
163  	return _PushNode(new(nothrow) DoubleValueNode(value), true);
164  }
165  
166  
167  // Pushes a string onto the predicate stack.
168  status_t
169  BQuery::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.
176  status_t
177  BQuery::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.
187  status_t
188  BQuery::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.
205  status_t
206  BQuery::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.
218  status_t
219  BQuery::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.
236  bool
237  BQuery::IsLive() const
238  {
239  	return fLive;
240  }
241  
242  
243  // Fills out buffer with the predicate string assigned to the BQuery object.
244  status_t
245  BQuery::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.
262  status_t
263  BQuery::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.
277  size_t
278  BQuery::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.
291  dev_t
292  BQuery::TargetDevice() const
293  {
294  	return fDevice;
295  }
296  
297  
298  // Start fetching entries satisfying the predicate.
299  status_t
300  BQuery::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.
329  status_t
330  BQuery::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.
344  status_t
345  BQuery::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.
374  int32
375  BQuery::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.
386  status_t
387  BQuery::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.
396  int32
397  BQuery::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  */
407  bool
408  BQuery::_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  */
435  status_t
436  BQuery::_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  */
465  status_t
466  BQuery::_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  */
495  status_t
496  BQuery::_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  */
523  void
524  BQuery::_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
559  void BQuery::_QwertyQuery1() {}
560  void BQuery::_QwertyQuery2() {}
561  void BQuery::_QwertyQuery3() {}
562  void BQuery::_QwertyQuery4() {}
563  void BQuery::_QwertyQuery5() {}
564  void BQuery::_QwertyQuery6() {}
565  
566