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.
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.
~BQuery()51 BQuery::~BQuery()
52 {
53 Clear();
54 }
55
56
57 // Resets the object to a uninitialized state.
58 status_t
Clear()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
PushAttr(const char * attrName)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
PushOp(query_op op)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
PushUInt32(uint32 value)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
PushInt32(int32 value)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
PushUInt64(uint64 value)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
PushInt64(int64 value)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
PushFloat(float value)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
PushDouble(double value)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
PushString(const char * value,bool caseInsensitive)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
PushDate(const char * date)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
SetVolume(const BVolume * volume)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
SetPredicate(const char * expression)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
SetTarget(BMessenger messenger)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
IsLive() const237 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
GetPredicate(char * buffer,size_t length)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
GetPredicate(BString * predicate)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
PredicateLength()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
TargetDevice() const292 BQuery::TargetDevice() const
293 {
294 return fDevice;
295 }
296
297
298 // Start fetching entries satisfying the predicate.
299 status_t
Fetch()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
GetNextEntry(BEntry * entry,bool traverse)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
GetNextRef(entry_ref * ref)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
GetNextDirents(struct dirent * buffer,size_t length,int32 count)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
Rewind()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
CountEntries()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
_HasFetched() const408 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
_PushNode(QueryNode * node,bool deleteOnError)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
_SetPredicate(const char * expression)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
_EvaluateStack()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
_ParseDates(BString & parsedPredicate)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
_QwertyQuery1()559 void BQuery::_QwertyQuery1() {}
_QwertyQuery2()560 void BQuery::_QwertyQuery2() {}
_QwertyQuery3()561 void BQuery::_QwertyQuery3() {}
_QwertyQuery4()562 void BQuery::_QwertyQuery4() {}
_QwertyQuery5()563 void BQuery::_QwertyQuery5() {}
_QwertyQuery6()564 void BQuery::_QwertyQuery6() {}
565
566