1 /* 2 * Copyright 2001-2014, Axel Dörfler, axeld@pinc-software.de. 3 * Copyright 2010, Clemens Zeidler <haiku@clemens-zeidler.de> 4 * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. 5 * This file may be used under the terms of the MIT License. 6 */ 7 #ifndef _FILE_SYSTEMS_QUERY_PARSER_H 8 #define _FILE_SYSTEMS_QUERY_PARSER_H 9 10 11 /*! Query parsing and evaluation. */ 12 13 14 // The operator precedence is =,!=,>,<,>=,<= .. && .. ||. 15 // Apparently, the "!" (not) can only be used with parentheses. 16 // 17 // If you think that there are too few NULL pointer checks in some places 18 // of the code, just read the beginning of the query constructor. 19 // The API is not fully available, just the Query and the Expression class 20 // are. 21 22 #ifdef FS_SHELL 23 # include <new> 24 25 # include "fssh_api_wrapper.h" 26 # include "fssh_auto_deleter.h" 27 #else 28 # include <dirent.h> 29 # include <stdlib.h> 30 # include <string.h> 31 32 # include <algorithm> 33 # include <new> 34 35 # include <fs_interface.h> 36 # include <fs_query.h> 37 # include <TypeConstants.h> 38 39 # include <util/SinglyLinkedList.h> 40 # include <util/Stack.h> 41 42 # include <query_private.h> 43 #endif // !FS_SHELL 44 45 #include <file_systems/QueryParserUtils.h> 46 47 48 //#define DEBUG_QUERY 49 50 #ifndef QUERY_RETURN_ERROR 51 # define QUERY_RETURN_ERROR(error) return (error) 52 #endif 53 54 #ifndef QUERY_REPORT_ERROR 55 # define QUERY_REPORT_ERROR(error) do {} while (false) 56 #endif 57 58 #ifndef QUERY_FATAL 59 # define QUERY_FATAL(message...) panic(message) 60 #endif 61 62 #ifndef QUERY_INFORM 63 # define QUERY_INFORM(message...) dprintf(message) 64 #endif 65 66 #ifndef QUERY_D 67 # define QUERY_D(block) 68 #endif 69 70 71 namespace QueryParser { 72 73 74 template<typename QueryPolicy> class Equation; 75 template<typename QueryPolicy> class Expression; 76 template<typename QueryPolicy> class Term; 77 template<typename QueryPolicy> class Query; 78 79 80 enum ops { 81 OP_NONE, 82 83 OP_AND, 84 OP_OR, 85 86 OP_EQUATION, 87 // is only used for invalid equations 88 89 OP_EQUAL, 90 OP_UNEQUAL, 91 OP_GREATER_THAN, 92 OP_LESS_THAN, 93 OP_GREATER_THAN_OR_EQUAL, 94 OP_LESS_THAN_OR_EQUAL, 95 }; 96 97 98 template<typename QueryPolicy> 99 union value { 100 int64 Int64; 101 uint64 Uint64; 102 int32 Int32; 103 uint32 Uint32; 104 float Float; 105 double Double; 106 char String[QueryPolicy::kMaxFileNameLength]; 107 }; 108 109 110 template<typename QueryPolicy> 111 class Query { 112 public: 113 typedef typename QueryPolicy::Entry Entry; 114 typedef typename QueryPolicy::Index Index; 115 typedef typename QueryPolicy::IndexIterator IndexIterator; 116 typedef typename QueryPolicy::Node Node; 117 typedef typename QueryPolicy::NodeHolder NodeHolder; 118 typedef typename QueryPolicy::Context Context; 119 120 public: 121 Query(Context* context, 122 Expression<QueryPolicy>* expression, 123 uint32 flags, port_id port, uint32 token); 124 ~Query(); 125 126 static status_t Create(Context* context, const char* queryString, 127 uint32 flags, port_id port, uint32 token, 128 Query<QueryPolicy>*& _query); 129 130 status_t Rewind(); 131 inline status_t GetNextEntry(struct dirent* dirent, size_t size); 132 133 void LiveUpdate(Entry* entry, Node* node, 134 const char* attribute, int32 type, 135 const uint8* oldKey, size_t oldLength, 136 const uint8* newKey, size_t newLength); 137 void LiveUpdateRenameMove(Entry* entry, Node* node, 138 ino_t oldDirectoryID, const char* oldName, 139 size_t oldLength, ino_t newDirectoryID, 140 const char* newName, size_t newLength); 141 142 Expression<QueryPolicy>* GetExpression() const 143 { return fExpression; } 144 145 uint32 Flags() const 146 { return fFlags; } 147 148 private: 149 status_t _GetNextEntry(struct dirent* dirent, size_t size); 150 void _SendEntryNotification(Entry* entry, 151 status_t (*notify)(port_id, int32, dev_t, ino_t, 152 const char*, ino_t)); 153 154 private: 155 Context* fContext; 156 Expression<QueryPolicy>* fExpression; 157 Equation<QueryPolicy>* fCurrent; 158 IndexIterator* fIterator; 159 Index fIndex; 160 Stack<Equation<QueryPolicy>*> fStack; 161 162 uint32 fFlags; 163 port_id fPort; 164 int32 fToken; 165 bool fNeedsEntry; 166 }; 167 168 169 /*! Abstract base class for the operator/equation classes. 170 */ 171 template<typename QueryPolicy> 172 class Term { 173 public: 174 typedef typename QueryPolicy::Entry Entry; 175 typedef typename QueryPolicy::Index Index; 176 typedef typename QueryPolicy::IndexIterator IndexIterator; 177 typedef typename QueryPolicy::Node Node; 178 typedef typename QueryPolicy::NodeHolder NodeHolder; 179 typedef typename QueryPolicy::Context Context; 180 181 public: 182 Term(int8 op) : fOp(op), fParent(NULL) {} 183 virtual ~Term() {} 184 185 int8 Op() const { return fOp; } 186 187 void SetParent(Term<QueryPolicy>* parent) 188 { fParent = parent; } 189 Term<QueryPolicy>* Parent() const { return fParent; } 190 191 virtual status_t Match(Entry* entry, Node* node, 192 const char* attribute = NULL, int32 type = 0, 193 const uint8* key = NULL, size_t size = 0) = 0; 194 virtual void Complement() = 0; 195 196 virtual void CalculateScore(Index& index) = 0; 197 virtual int32 Score() const = 0; 198 199 virtual status_t InitCheck() = 0; 200 201 virtual bool NeedsEntry() = 0; 202 203 #ifdef DEBUG_QUERY 204 virtual void PrintToStream() = 0; 205 #endif 206 207 protected: 208 int8 fOp; 209 Term<QueryPolicy>* fParent; 210 }; 211 212 213 /*! An Equation object represents an "attribute-equation operator-value" pair. 214 215 Although an Equation object is quite independent from the volume on which 216 the query is run, there are some dependencies that are produced while 217 querying: 218 The type/size of the value, the score, and if it has an index or not. 219 So you could run more than one query on the same volume, but it might return 220 wrong values when it runs concurrently on another volume. 221 That's not an issue right now, because we run single-threaded and don't use 222 queries more than once. 223 */ 224 template<typename QueryPolicy> 225 class Equation : public Term<QueryPolicy> { 226 public: 227 typedef typename QueryPolicy::Entry Entry; 228 typedef typename QueryPolicy::Index Index; 229 typedef typename QueryPolicy::IndexIterator IndexIterator; 230 typedef typename QueryPolicy::Node Node; 231 typedef typename QueryPolicy::NodeHolder NodeHolder; 232 typedef typename QueryPolicy::Context Context; 233 234 public: 235 Equation(const char** expression); 236 virtual ~Equation(); 237 238 virtual status_t InitCheck(); 239 240 status_t ParseQuotedString(const char** _start, const char** _end); 241 char* CopyString(const char* start, const char* end); 242 inline bool _IsEquationChar(char c) const; 243 inline bool _IsOperatorChar(char c) const; 244 245 virtual status_t Match(Entry* entry, Node* node, 246 const char* attribute = NULL, int32 type = 0, 247 const uint8* key = NULL, size_t size = 0); 248 virtual void Complement(); 249 250 status_t PrepareQuery(Context* context, Index& index, 251 IndexIterator** iterator, bool queryNonIndexed); 252 status_t GetNextMatching(Context* context, 253 IndexIterator* iterator, struct dirent* dirent, 254 size_t bufferSize); 255 256 virtual void CalculateScore(Index &index); 257 virtual int32 Score() const { return fScore; } 258 259 virtual bool NeedsEntry(); 260 261 #ifdef DEBUG_QUERY 262 virtual void PrintToStream(); 263 #endif 264 265 private: 266 Equation(const Equation& other); 267 Equation& operator=(const Equation& other); 268 // no implementation 269 270 status_t ConvertValue(type_code type); 271 bool CompareTo(const uint8* value, size_t size); 272 uint8* Value() const { return (uint8*)&fValue; } 273 274 char* fAttribute; 275 char* fString; 276 union value<QueryPolicy> fValue; 277 type_code fType; 278 size_t fSize; 279 bool fIsPattern; 280 281 int32 fScore; 282 bool fHasIndex; 283 }; 284 285 286 /*! The Operator class does not represent a generic operator, but only those 287 that combine two equations, namely "or", and "and". 288 */ 289 template<typename QueryPolicy> 290 class Operator : public Term<QueryPolicy> { 291 public: 292 typedef typename QueryPolicy::Entry Entry; 293 typedef typename QueryPolicy::Index Index; 294 typedef typename QueryPolicy::IndexIterator IndexIterator; 295 typedef typename QueryPolicy::Node Node; 296 typedef typename QueryPolicy::Context Context; 297 298 public: 299 Operator(Term<QueryPolicy>* left, int8 op, 300 Term<QueryPolicy>* right); 301 virtual ~Operator(); 302 303 Term<QueryPolicy>* Left() const { return fLeft; } 304 Term<QueryPolicy>* Right() const { return fRight; } 305 306 virtual status_t Match(Entry* entry, Node* node, 307 const char* attribute = NULL, int32 type = 0, 308 const uint8* key = NULL, size_t size = 0); 309 virtual void Complement(); 310 311 virtual void CalculateScore(Index& index); 312 virtual int32 Score() const; 313 314 virtual status_t InitCheck(); 315 316 virtual bool NeedsEntry(); 317 318 #ifdef DEBUG_QUERY 319 virtual void PrintToStream(); 320 #endif 321 322 private: 323 Operator(const Operator& other); 324 Operator& operator=(const Operator& other); 325 // no implementation 326 327 Term<QueryPolicy>* fLeft; 328 Term<QueryPolicy>* fRight; 329 }; 330 331 332 template<typename QueryPolicy> 333 class Expression { 334 public: 335 typedef typename QueryPolicy::Entry Entry; 336 typedef typename QueryPolicy::Index Index; 337 typedef typename QueryPolicy::IndexIterator IndexIterator; 338 typedef typename QueryPolicy::Node Node; 339 typedef typename QueryPolicy::Context Context; 340 341 public: 342 Expression(); 343 ~Expression(); 344 345 status_t Init(const char* expr, const char** position); 346 347 Term<QueryPolicy>* Root() const { return fTerm; } 348 349 protected: 350 bool IsOperator(const char** expr, char op); 351 352 private: 353 Expression(const Expression& other); 354 Expression& operator=(const Expression& other); 355 // no implementation 356 357 Term<QueryPolicy>* fTerm; 358 }; 359 360 361 // #pragma mark - 362 363 364 template<typename QueryPolicy> 365 Equation<QueryPolicy>::Equation(const char** expr) 366 : 367 Term<QueryPolicy>(OP_EQUATION), 368 fAttribute(NULL), 369 fString(NULL), 370 fType(0), 371 fIsPattern(false) 372 { 373 const char* string = *expr; 374 const char* start = string; 375 const char* end = NULL; 376 377 // Since the equation is the integral part of any query, we're just parsing 378 // the whole thing here. 379 // The whitespace at the start is already removed in 380 // Expression::ParseEquation() 381 382 if (*start == '"' || *start == '\'') { 383 // string is quoted (start has to be on the beginning of a string) 384 if (ParseQuotedString(&start, &end) < B_OK) 385 return; 386 387 // set string to a valid start of the equation symbol 388 string = end + 2; 389 skipWhitespace(&string); 390 if (!_IsEquationChar(string[0])) { 391 *expr = string; 392 return; 393 } 394 } else { 395 // search the (in)equation for the actual equation symbol (and for other operators 396 // in case the equation is malformed) 397 while (string[0] != 0 && !_IsOperatorChar(string[0]) 398 && !_IsEquationChar(string[0])) { 399 if (string[0] == '\\' && string[1] != 0) 400 string++; 401 string++; 402 } 403 404 // get the attribute string (and trim whitespace), in case 405 // the string was not quoted 406 end = string - 1; 407 skipWhitespaceReverse(&end, start); 408 } 409 410 // attribute string is empty (which is not allowed) 411 if (start > end) 412 return; 413 414 // At this point, "start" points to the beginning of the string, "end" 415 // points to the last character of the string, and "string" points to the 416 // first character of the equation symbol 417 418 // test for the right symbol (as this doesn't need any memory) 419 switch (*string) { 420 case '=': 421 Term<QueryPolicy>::fOp = OP_EQUAL; 422 break; 423 case '>': 424 Term<QueryPolicy>::fOp = *(string + 1) == '=' 425 ? OP_GREATER_THAN_OR_EQUAL : OP_GREATER_THAN; 426 break; 427 case '<': 428 Term<QueryPolicy>::fOp = *(string + 1) == '=' 429 ? OP_LESS_THAN_OR_EQUAL : OP_LESS_THAN; 430 break; 431 case '!': 432 if (*(string + 1) != '=') 433 return; 434 Term<QueryPolicy>::fOp = OP_UNEQUAL; 435 break; 436 437 // any invalid characters will be rejected 438 default: 439 *expr = string; 440 return; 441 } 442 443 // lets change "start" to point to the first character after the symbol 444 if (*(string + 1) == '=') 445 string++; 446 string++; 447 skipWhitespace(&string); 448 449 // allocate & copy the attribute string 450 451 fAttribute = CopyString(start, end); 452 if (fAttribute == NULL) 453 return; 454 455 start = string; 456 if (*start == '"' || *start == '\'') { 457 // string is quoted (start has to be on the beginning of a string) 458 if (ParseQuotedString(&start, &end) < B_OK) 459 return; 460 461 string = end + 2; 462 skipWhitespace(&string); 463 } else { 464 while (string[0] && !_IsOperatorChar(string[0]) && string[0] != ')') 465 string++; 466 467 end = string - 1; 468 skipWhitespaceReverse(&end, start); 469 } 470 471 // at this point, "start" will point to the first character of the value, 472 // "end" will point to its last character, and "start" to the first non- 473 // whitespace character after the value string 474 475 fString = CopyString(start, end); 476 if (fString == NULL) 477 return; 478 479 // patterns are only allowed for these operations (and strings) 480 if (Term<QueryPolicy>::fOp == OP_EQUAL 481 || Term<QueryPolicy>::fOp == OP_UNEQUAL) { 482 fIsPattern = isPattern(fString); 483 if (fIsPattern && isValidPattern(fString) < B_OK) { 484 // we only want to have valid patterns; setting fString 485 // to NULL will cause InitCheck() to fail 486 free(fString); 487 fString = NULL; 488 } 489 } 490 491 *expr = string; 492 } 493 494 495 template<typename QueryPolicy> 496 Equation<QueryPolicy>::~Equation() 497 { 498 free(fAttribute); 499 free(fString); 500 } 501 502 503 template<typename QueryPolicy> 504 status_t 505 Equation<QueryPolicy>::InitCheck() 506 { 507 if (fAttribute == NULL || fString == NULL 508 || Term<QueryPolicy>::fOp == OP_NONE) { 509 return B_BAD_VALUE; 510 } 511 512 return B_OK; 513 } 514 515 516 template<typename QueryPolicy> 517 status_t 518 Equation<QueryPolicy>::ParseQuotedString(const char** _start, const char** _end) 519 { 520 const char* start = *_start; 521 const char quote = *start++; 522 const char* end = start; 523 524 for (; *end && *end != quote; end++) { 525 if (*end == '\\') 526 end++; 527 } 528 if (*end == '\0') 529 return B_BAD_VALUE; 530 531 *_start = start; 532 *_end = end - 1; 533 534 return B_OK; 535 } 536 537 538 template<typename QueryPolicy> 539 char* 540 Equation<QueryPolicy>::CopyString(const char* start, const char* end) 541 { 542 // end points to the last character of the string - and the length 543 // also has to include the null-termination 544 int32 length = end + 2 - start; 545 // just to make sure; since that's the max. attribute name length and 546 // the max. string in an index, it make sense to have it that way 547 if (length > QueryPolicy::kMaxFileNameLength || length <= 0) 548 return NULL; 549 550 char* copy = (char*)malloc(length); 551 if (copy == NULL) 552 return NULL; 553 554 // Filter out remaining escaping slashes 555 for (int32 i = 0; i < length; i++) { 556 char c = start++[0]; 557 if (c == '\\' && i < length) { 558 length--; 559 i--; 560 continue; 561 } 562 copy[i] = c; 563 } 564 copy[length - 1] = '\0'; 565 566 return copy; 567 } 568 569 570 template<typename QueryPolicy> 571 bool 572 Equation<QueryPolicy>::_IsEquationChar(char c) const 573 { 574 return c == '=' || c == '<' || c == '>' || c == '!'; 575 } 576 577 578 template<typename QueryPolicy> 579 bool 580 Equation<QueryPolicy>::_IsOperatorChar(char c) const 581 { 582 return c == '&' || c == '|'; 583 } 584 585 586 template<typename QueryPolicy> 587 status_t 588 Equation<QueryPolicy>::ConvertValue(type_code type) 589 { 590 // Has the type already been converted? 591 if (type == fType) 592 return B_OK; 593 594 char* string = fString; 595 596 switch (type) { 597 case B_MIME_STRING_TYPE: 598 type = B_STRING_TYPE; 599 // supposed to fall through 600 case B_STRING_TYPE: 601 strncpy(fValue.String, string, QueryPolicy::kMaxFileNameLength); 602 fValue.String[QueryPolicy::kMaxFileNameLength - 1] = '\0'; 603 fSize = strlen(fValue.String); 604 break; 605 case B_INT32_TYPE: 606 fValue.Int32 = strtol(string, &string, 0); 607 fSize = sizeof(int32); 608 break; 609 case B_UINT32_TYPE: 610 fValue.Int32 = strtoul(string, &string, 0); 611 fSize = sizeof(uint32); 612 break; 613 case B_TIME_TYPE: 614 type = B_INT64_TYPE; 615 // supposed to fall through 616 case B_INT64_TYPE: 617 fValue.Int64 = strtoll(string, &string, 0); 618 fSize = sizeof(int64); 619 break; 620 case B_UINT64_TYPE: 621 fValue.Uint64 = strtoull(string, &string, 0); 622 fSize = sizeof(uint64); 623 break; 624 case B_FLOAT_TYPE: 625 fValue.Float = strtod(string, &string); 626 fSize = sizeof(float); 627 break; 628 case B_DOUBLE_TYPE: 629 fValue.Double = strtod(string, &string); 630 fSize = sizeof(double); 631 break; 632 default: 633 QUERY_INFORM("query attribute '%s': unsupported value conversion to 0x%x requested!\n", 634 fAttribute, (int)type); 635 return B_BAD_TYPE; 636 } 637 638 fType = type; 639 640 // patterns are only allowed for string types 641 if (fType != B_STRING_TYPE && fIsPattern) 642 fIsPattern = false; 643 644 return B_OK; 645 } 646 647 648 /*! Returns true when the key matches the equation. You have to 649 call ConvertValue() before this one. 650 */ 651 template<typename QueryPolicy> 652 bool 653 Equation<QueryPolicy>::CompareTo(const uint8* value, size_t size) 654 { 655 int32 compare; 656 657 // fIsPattern is only true if it's a string type, and fOp OP_EQUAL, or 658 // OP_UNEQUAL 659 if (fIsPattern) { 660 // we have already validated the pattern, so we don't check for failing 661 // here - if something is broken, and matchString() returns an error, 662 // we just don't match 663 compare = matchString(fValue.String, (const char*)value) == MATCH_OK ? 0 : 1; 664 } else 665 compare = compareKeys(fType, value, size, Value(), fSize); 666 667 switch (Term<QueryPolicy>::fOp) { 668 case OP_EQUAL: 669 return compare == 0; 670 case OP_UNEQUAL: 671 return compare != 0; 672 case OP_LESS_THAN: 673 return compare < 0; 674 case OP_LESS_THAN_OR_EQUAL: 675 return compare <= 0; 676 case OP_GREATER_THAN: 677 return compare > 0; 678 case OP_GREATER_THAN_OR_EQUAL: 679 return compare >= 0; 680 } 681 QUERY_FATAL("Unknown/Unsupported operation: %d\n", Term<QueryPolicy>::fOp); 682 return false; 683 } 684 685 686 template<typename QueryPolicy> 687 void 688 Equation<QueryPolicy>::Complement() 689 { 690 QUERY_D(if (Term<QueryPolicy>::fOp <= OP_EQUATION || Term<QueryPolicy>::fOp > OP_LESS_THAN_OR_EQUAL) { 691 QUERY_FATAL("op out of range!\n"); 692 return; 693 }); 694 695 int8 complementOp[] = {OP_UNEQUAL, OP_EQUAL, OP_LESS_THAN_OR_EQUAL, 696 OP_GREATER_THAN_OR_EQUAL, OP_LESS_THAN, OP_GREATER_THAN}; 697 Term<QueryPolicy>::fOp = complementOp[Term<QueryPolicy>::fOp - OP_EQUAL]; 698 } 699 700 701 /*! Matches the node's attribute value with the equation. 702 Returns MATCH_OK if it matches, NO_MATCH if not, < 0 if something went 703 wrong. 704 */ 705 template<typename QueryPolicy> 706 status_t 707 Equation<QueryPolicy>::Match(Entry* entry, Node* node, 708 const char* attributeName, int32 type, const uint8* key, size_t size) 709 { 710 // get a pointer to the attribute in question 711 NodeHolder nodeHolder; 712 union value<QueryPolicy> value; 713 uint8* buffer = (uint8*)&value; 714 const size_t bufferSize = sizeof(value); 715 716 // first, check if we are matching for a live query and use that value 717 if (attributeName != NULL && !strcmp(fAttribute, attributeName)) { 718 if (key == NULL) 719 return NO_MATCH; 720 buffer = const_cast<uint8*>(key); 721 } else if (!strcmp(fAttribute, "name")) { 722 // if not, check for "fake" attributes ("name", "size", "last_modified") 723 if (entry == NULL) 724 return B_ERROR; 725 buffer = (uint8*)QueryPolicy::EntryGetNameNoCopy(nodeHolder, entry); 726 if (buffer == NULL) 727 return B_ERROR; 728 729 type = B_STRING_TYPE; 730 size = strlen((const char*)buffer); 731 } else if (!strcmp(fAttribute, "size")) { 732 value.Int64 = QueryPolicy::NodeGetSize(node); 733 type = B_INT64_TYPE; 734 } else if (!strcmp(fAttribute, "last_modified")) { 735 value.Int64 = QueryPolicy::NodeGetLastModifiedTime(node); 736 type = B_INT64_TYPE; 737 } else { 738 // then for attributes 739 size = bufferSize; 740 if (QueryPolicy::NodeGetAttribute(nodeHolder, node, 741 fAttribute, buffer, &size, &type) != B_OK) { 742 return NO_MATCH; 743 } 744 } 745 746 // prepare own value for use, if it is possible to convert it 747 status_t status = ConvertValue(type); 748 if (status == B_OK) 749 status = CompareTo(buffer, size) ? MATCH_OK : NO_MATCH; 750 751 QUERY_RETURN_ERROR(status); 752 } 753 754 755 template<typename QueryPolicy> 756 void 757 Equation<QueryPolicy>::CalculateScore(Index &index) 758 { 759 // As always, these values could be tuned and refined. 760 // And the code could also need some real world testing :-) 761 762 // do we have to operate on a "foreign" index? 763 if (Term<QueryPolicy>::fOp == OP_UNEQUAL 764 || QueryPolicy::IndexSetTo(index, fAttribute) < B_OK) { 765 fScore = 0; 766 return; 767 } 768 769 // if we have a pattern, how much does it help our search? 770 if (fIsPattern) { 771 fScore = getFirstPatternSymbol(fString) << 3; 772 773 // Even if the first pattern symbol is at position 0, 774 // there's still an index, so don't let our score revert to zero. 775 if (fScore == 0) 776 fScore = 1; 777 } else { 778 // Score by operator 779 if (Term<QueryPolicy>::fOp == OP_EQUAL) { 780 // higher than pattern="255 chars+*" 781 fScore = 2048; 782 } else { 783 // the pattern search is regarded cheaper when you have at 784 // least one character to set your index to 785 fScore = 5; 786 } 787 } 788 789 // take index size into account 790 fScore = QueryPolicy::IndexGetWeightedScore(index, fScore); 791 } 792 793 794 template<typename QueryPolicy> 795 status_t 796 Equation<QueryPolicy>::PrepareQuery(Context* /*context*/, Index& index, 797 IndexIterator** iterator, bool queryNonIndexed) 798 { 799 status_t status = QueryPolicy::IndexSetTo(index, fAttribute); 800 801 // if we should query attributes without an index, we can just proceed here 802 if (status != B_OK && !queryNonIndexed) 803 return B_ENTRY_NOT_FOUND; 804 805 type_code type; 806 807 // Special case for OP_UNEQUAL - it will always operate through the whole 808 // index but we need the call to the original index to get the correct type 809 if (status != B_OK || Term<QueryPolicy>::fOp == OP_UNEQUAL) { 810 // Try to get an index that holds all files (name) 811 // Also sets the default type for all attributes without index 812 // to string. 813 type = status < B_OK ? B_STRING_TYPE : QueryPolicy::IndexGetType(index); 814 815 if (QueryPolicy::IndexSetTo(index, "name") != B_OK) 816 return B_ENTRY_NOT_FOUND; 817 818 fHasIndex = false; 819 } else { 820 fHasIndex = true; 821 type = QueryPolicy::IndexGetType(index); 822 } 823 824 if (ConvertValue(type) < B_OK) 825 return B_BAD_VALUE; 826 827 *iterator = QueryPolicy::IndexCreateIterator(index); 828 if (*iterator == NULL) 829 return B_NO_MEMORY; 830 831 if ((Term<QueryPolicy>::fOp == OP_EQUAL 832 || Term<QueryPolicy>::fOp == OP_GREATER_THAN 833 || Term<QueryPolicy>::fOp == OP_GREATER_THAN_OR_EQUAL || fIsPattern) 834 && fHasIndex) { 835 // set iterator to the exact position 836 837 int32 keySize = QueryPolicy::IndexGetKeySize(index); 838 839 // At this point, fIsPattern is only true if it's a string type, and fOp 840 // is either OP_EQUAL or OP_UNEQUAL 841 if (fIsPattern) { 842 // let's see if we can use the beginning of the key for positioning 843 // the iterator and adjust the key size; if not, just leave the 844 // iterator at the start and return success 845 keySize = getFirstPatternSymbol(fString); 846 if (keySize <= 0) 847 return B_OK; 848 } 849 850 if (keySize == 0) { 851 // B_STRING_TYPE doesn't have a fixed length, so it was set 852 // to 0 before - we compute the correct value here 853 if (fType == B_STRING_TYPE) { 854 keySize = strlen(fValue.String); 855 856 // The empty string is a special case - we normally don't check 857 // for the trailing null byte, in the case for the empty string 858 // we do it explicitly, because there can't be keys in the 859 // B+tree with a length of zero 860 if (keySize == 0) 861 keySize = 1; 862 } else 863 QUERY_RETURN_ERROR(B_ENTRY_NOT_FOUND); 864 } 865 866 status = QueryPolicy::IndexIteratorFind(*iterator, Value(), keySize); 867 if (Term<QueryPolicy>::fOp == OP_EQUAL && !fIsPattern) 868 return status; 869 else if (status == B_ENTRY_NOT_FOUND 870 && (fIsPattern || Term<QueryPolicy>::fOp == OP_GREATER_THAN 871 || Term<QueryPolicy>::fOp == OP_GREATER_THAN_OR_EQUAL)) 872 return B_OK; 873 874 QUERY_RETURN_ERROR(status); 875 } 876 877 return B_OK; 878 } 879 880 881 template<typename QueryPolicy> 882 status_t 883 Equation<QueryPolicy>::GetNextMatching(Context* context, 884 IndexIterator* iterator, struct dirent* dirent, size_t bufferSize) 885 { 886 while (true) { 887 NodeHolder nodeHolder; 888 union value<QueryPolicy> indexValue; 889 size_t keyLength; 890 size_t duplicate = 0; 891 892 status_t status = QueryPolicy::IndexIteratorFetchNextEntry(iterator, 893 &indexValue, &keyLength, (size_t)sizeof(indexValue), &duplicate); 894 if (status != B_OK) 895 return status; 896 897 // only compare against the index entry when this is the correct 898 // index for the equation 899 if (fHasIndex && duplicate < 2 && !CompareTo((uint8*)&indexValue, keyLength)) { 900 // They aren't equal? Let the operation decide what to do. Since 901 // we always start at the beginning of the index (or the correct 902 // position), only some needs to be stopped if the entry doesn't 903 // fit. 904 if (Term<QueryPolicy>::fOp == OP_LESS_THAN 905 || Term<QueryPolicy>::fOp == OP_LESS_THAN_OR_EQUAL 906 || (Term<QueryPolicy>::fOp == OP_EQUAL && !fIsPattern)) 907 return B_ENTRY_NOT_FOUND; 908 909 if (duplicate > 0) 910 QueryPolicy::IndexIteratorSkipDuplicates(iterator); 911 continue; 912 } 913 914 Entry* entry = NULL; 915 status = QueryPolicy::IndexIteratorGetEntry(context, iterator, 916 nodeHolder, &entry); 917 if (status != B_OK) { 918 // try with next 919 continue; 920 } 921 922 // TODO: check user permissions here - but which one?! 923 // we could filter out all those where we don't have 924 // read access... (we should check for every parent 925 // directory if the X_OK is allowed) 926 // Although it's quite expensive to open all parents, 927 // it's likely that the application that runs the 928 // query will do something similar (and we don't have 929 // to do it for root, either). 930 931 // go up in the tree until a &&-operator is found, and check if the 932 // node matches with the rest of the expression - we don't have to 933 // check ||-operators for that 934 Term<QueryPolicy>* term = this; 935 status = MATCH_OK; 936 937 if (!fHasIndex) 938 status = Match(entry, QueryPolicy::EntryGetNode(entry)); 939 940 while (term != NULL && status == MATCH_OK) { 941 Operator<QueryPolicy>* parent 942 = (Operator<QueryPolicy>*)term->Parent(); 943 if (parent == NULL) 944 break; 945 946 if (parent->Op() == OP_AND) { 947 // choose the other child of the parent 948 Term<QueryPolicy>* other = parent->Right(); 949 if (other == term) 950 other = parent->Left(); 951 952 if (other == NULL) { 953 QUERY_FATAL("&&-operator has only one child... " 954 "(parent = %p)\n", parent); 955 break; 956 } 957 status = other->Match(entry, QueryPolicy::EntryGetNode(entry)); 958 if (status < 0) { 959 QUERY_REPORT_ERROR(status); 960 status = NO_MATCH; 961 } 962 } 963 term = (Term<QueryPolicy>*)parent; 964 } 965 966 if (status == MATCH_OK) { 967 ssize_t nameLength = QueryPolicy::EntryGetName(entry, 968 dirent->d_name, 969 (const char*)dirent + bufferSize - dirent->d_name); 970 if (nameLength < 0) { 971 // Invalid or unknown name. 972 nameLength = 0; 973 } 974 975 dirent->d_dev = QueryPolicy::ContextGetVolumeID(context); 976 dirent->d_ino = QueryPolicy::EntryGetNodeID(entry); 977 dirent->d_pdev = dirent->d_dev; 978 dirent->d_pino = QueryPolicy::EntryGetParentID(entry); 979 dirent->d_reclen = offsetof(struct dirent, d_name) + nameLength; 980 } 981 982 if (status == MATCH_OK) 983 return B_OK; 984 } 985 QUERY_RETURN_ERROR(B_ERROR); 986 } 987 988 989 template<typename QueryPolicy> 990 bool 991 Equation<QueryPolicy>::NeedsEntry() 992 { 993 return strcmp(fAttribute, "name") == 0; 994 } 995 996 997 // #pragma mark - 998 999 1000 template<typename QueryPolicy> 1001 Operator<QueryPolicy>::Operator(Term<QueryPolicy>* left, int8 op, 1002 Term<QueryPolicy>* right) 1003 : 1004 Term<QueryPolicy>(op), 1005 fLeft(left), 1006 fRight(right) 1007 { 1008 if (left) 1009 left->SetParent(this); 1010 if (right) 1011 right->SetParent(this); 1012 } 1013 1014 1015 template<typename QueryPolicy> 1016 Operator<QueryPolicy>::~Operator() 1017 { 1018 delete fLeft; 1019 delete fRight; 1020 } 1021 1022 1023 template<typename QueryPolicy> 1024 status_t 1025 Operator<QueryPolicy>::Match(Entry* entry, Node* node, const char* attribute, 1026 int32 type, const uint8* key, size_t size) 1027 { 1028 if (Term<QueryPolicy>::fOp == OP_AND) { 1029 status_t status = fLeft->Match(entry, node, attribute, type, key, 1030 size); 1031 if (status != MATCH_OK) 1032 return status; 1033 1034 return fRight->Match(entry, node, attribute, type, key, size); 1035 } else { 1036 // choose the term with the better score for OP_OR 1037 Term<QueryPolicy>* first; 1038 Term<QueryPolicy>* second; 1039 if (fRight->Score() > fLeft->Score()) { 1040 first = fLeft; 1041 second = fRight; 1042 } else { 1043 first = fRight; 1044 second = fLeft; 1045 } 1046 1047 status_t status = first->Match(entry, node, attribute, type, key, 1048 size); 1049 if (status != NO_MATCH) 1050 return status; 1051 1052 return second->Match(entry, node, attribute, type, key, size); 1053 } 1054 } 1055 1056 1057 template<typename QueryPolicy> 1058 void 1059 Operator<QueryPolicy>::Complement() 1060 { 1061 if (Term<QueryPolicy>::fOp == OP_AND) 1062 Term<QueryPolicy>::fOp = OP_OR; 1063 else 1064 Term<QueryPolicy>::fOp = OP_AND; 1065 1066 fLeft->Complement(); 1067 fRight->Complement(); 1068 } 1069 1070 1071 template<typename QueryPolicy> 1072 void 1073 Operator<QueryPolicy>::CalculateScore(Index &index) 1074 { 1075 fLeft->CalculateScore(index); 1076 fRight->CalculateScore(index); 1077 } 1078 1079 1080 template<typename QueryPolicy> 1081 int32 1082 Operator<QueryPolicy>::Score() const 1083 { 1084 if (Term<QueryPolicy>::fOp == OP_AND) { 1085 // return the one with the better score 1086 if (fRight->Score() > fLeft->Score()) 1087 return fRight->Score(); 1088 1089 return fLeft->Score(); 1090 } 1091 1092 // for OP_OR, be honest, and return the one with the worse score 1093 if (fRight->Score() < fLeft->Score()) 1094 return fRight->Score(); 1095 1096 return fLeft->Score(); 1097 } 1098 1099 1100 template<typename QueryPolicy> 1101 status_t 1102 Operator<QueryPolicy>::InitCheck() 1103 { 1104 if ((Term<QueryPolicy>::fOp != OP_AND && Term<QueryPolicy>::fOp != OP_OR) 1105 || fLeft == NULL || fLeft->InitCheck() < B_OK 1106 || fRight == NULL || fRight->InitCheck() < B_OK) 1107 return B_ERROR; 1108 1109 return B_OK; 1110 } 1111 1112 1113 template<typename QueryPolicy> 1114 bool 1115 Operator<QueryPolicy>::NeedsEntry() 1116 { 1117 return ((fLeft && fLeft->NeedsEntry()) || (fRight && fRight->NeedsEntry())); 1118 } 1119 1120 1121 // #pragma mark - 1122 1123 #ifdef DEBUG_QUERY 1124 1125 template<typename QueryPolicy> 1126 void 1127 Operator<QueryPolicy>::PrintToStream() 1128 { 1129 QUERY_D(__out("( ")); 1130 if (fLeft != NULL) 1131 fLeft->PrintToStream(); 1132 1133 const char* op; 1134 switch (Term<QueryPolicy>::fOp) { 1135 case OP_OR: op = "OR"; break; 1136 case OP_AND: op = "AND"; break; 1137 default: op = "?"; break; 1138 } 1139 QUERY_D(__out(" %s ", op)); 1140 1141 if (fRight != NULL) 1142 fRight->PrintToStream(); 1143 1144 QUERY_D(__out(" )")); 1145 } 1146 1147 1148 template<typename QueryPolicy> 1149 void 1150 Equation<QueryPolicy>::PrintToStream() 1151 { 1152 const char* symbol = "???"; 1153 switch (Term<QueryPolicy>::fOp) { 1154 case OP_EQUAL: symbol = "=="; break; 1155 case OP_UNEQUAL: symbol = "!="; break; 1156 case OP_GREATER_THAN: symbol = ">"; break; 1157 case OP_GREATER_THAN_OR_EQUAL: symbol = ">="; break; 1158 case OP_LESS_THAN: symbol = "<"; break; 1159 case OP_LESS_THAN_OR_EQUAL: symbol = "<="; break; 1160 } 1161 QUERY_D(__out("[\"%s\" %s \"%s\"]", fAttribute, symbol, fString)); 1162 } 1163 1164 #endif // DEBUG_QUERY 1165 1166 // #pragma mark - 1167 1168 1169 template<typename QueryPolicy> 1170 Expression<QueryPolicy>::Expression() 1171 : 1172 fTerm(NULL) 1173 { 1174 } 1175 1176 1177 template<typename QueryPolicy> 1178 status_t 1179 Expression<QueryPolicy>::Init(const char* expr, const char** position) 1180 { 1181 if (expr == NULL) 1182 return B_BAD_VALUE; 1183 if (fTerm != NULL) 1184 return EALREADY; 1185 1186 status_t status = B_OK; 1187 int32 equations = 0; 1188 const int32 kMaxEquations = 32; 1189 1190 struct ExpressionNode { 1191 Term<QueryPolicy>* term = NULL; 1192 bool negated = false; 1193 ops op = OP_NONE; 1194 }; 1195 Stack<Stack<ExpressionNode>*> exprsTree; 1196 Stack<ExpressionNode>* currentExpr = NULL; 1197 ExpressionNode* current = NULL; 1198 while (expr != NULL) { 1199 skipWhitespace(&expr); 1200 1201 if (currentExpr == NULL) { 1202 currentExpr = new(std::nothrow) Stack<ExpressionNode>; 1203 if (currentExpr == NULL) { 1204 status = B_NO_MEMORY; 1205 break; 1206 } 1207 } 1208 1209 const char c = *expr; 1210 bool complete = false; 1211 1212 if (c == ')' || c == '\0') { 1213 if (currentExpr->IsEmpty()) 1214 break; // Illegal empty expression. 1215 1216 complete = true; 1217 } 1218 1219 if (current == NULL && !complete) { 1220 currentExpr->Push(ExpressionNode()); 1221 current = currentExpr->Array() + (currentExpr->CountItems() - 1); 1222 } 1223 1224 if (c == '(') { 1225 exprsTree.Push(currentExpr); 1226 currentExpr = NULL; 1227 current = NULL; 1228 expr++; 1229 } else if (c == '!') { 1230 skipWhitespace(&expr, 1); 1231 if (*expr != '(') 1232 break; // Not allowed. 1233 current->negated = true; 1234 } else if (c == '|' || c == '&') { 1235 if (current->term == NULL) 1236 break; // Nothing to operate on. 1237 1238 ops op = OP_NONE; 1239 if (IsOperator(&expr, '|')) 1240 op = OP_OR; 1241 else if (IsOperator(&expr, '&')) 1242 op = OP_AND; 1243 else 1244 break; // Illegal operator. 1245 1246 current->op = op; 1247 current = NULL; 1248 } else if (!complete) { 1249 if (current->term != NULL) 1250 break; // There already is a term. 1251 if ((equations + 1) > kMaxEquations) { 1252 status = E2BIG; 1253 break; 1254 } 1255 1256 Equation<QueryPolicy>* equation 1257 = new(std::nothrow) Equation<QueryPolicy>(&expr); 1258 if (equation == NULL) { 1259 status = B_NO_MEMORY; 1260 break; 1261 } 1262 if (equation == NULL || equation->InitCheck() != B_OK) { 1263 status = equation->InitCheck(); 1264 delete equation; 1265 break; 1266 } 1267 1268 current->term = equation; 1269 equations++; 1270 } 1271 if (!complete) 1272 continue; 1273 1274 if (currentExpr->CountItems() == 1) { 1275 if (current == NULL) 1276 break; // Probably an anomalous operator. 1277 } 1278 1279 // First pass: negation. 1280 for (int32 i = 0; i < currentExpr->CountItems(); i++) { 1281 current = currentExpr->Array() + i; 1282 // If the term is negated, we just complement the tree, to get 1283 // rid of the not, a.k.a. DeMorgan's Law. 1284 if (current->negated) { 1285 current->term->Complement(); 1286 current->negated = false; 1287 } 1288 } 1289 // Second & third passes: && and ||. 1290 int32 nodes = currentExpr->CountItems(); 1291 for (ops op = OP_AND; op <= OP_OR; op = (ops)(op + 1)) { 1292 for (int32 i = 0; i < (currentExpr->CountItems() - 1); ) { 1293 ExpressionNode* left = currentExpr->Array() + i; 1294 if (left->op != op) { 1295 i++; 1296 continue; 1297 } 1298 1299 // Find the right-hand expression (may have to jump over now-unused nodes.) 1300 ExpressionNode* right = NULL; 1301 for (int32 j = i + 1; j < currentExpr->CountItems(); j++) { 1302 current = currentExpr->Array() + j; 1303 if (current->term == NULL) 1304 continue; 1305 1306 right = current; 1307 break; 1308 } 1309 if (right == NULL) 1310 break; // Invalid expression, somehow. 1311 1312 Term<QueryPolicy>* newTerm = new(std::nothrow) Operator<QueryPolicy>( 1313 left->term, left->op, right->term); 1314 if (newTerm == NULL) { 1315 status = B_NO_MEMORY; 1316 break; 1317 } 1318 1319 left->term = newTerm; 1320 left->op = right->op; 1321 right->op = OP_NONE; 1322 right->term = NULL; 1323 nodes--; 1324 } 1325 } 1326 1327 // At this point we should have only one node left. 1328 if (nodes != 1) 1329 break; 1330 1331 current = currentExpr->Array(); 1332 Term<QueryPolicy>* term = current->term; 1333 1334 delete currentExpr; 1335 currentExpr = NULL; 1336 if (exprsTree.Pop(¤tExpr)) { 1337 current = currentExpr->Array() + (currentExpr->CountItems() - 1); 1338 if (current->term != NULL) 1339 break; // There already is a term. 1340 current->term = term; 1341 } else { 1342 if (c != '\0') 1343 break; // Unexpected end of expression. 1344 1345 fTerm = term; 1346 break; 1347 } 1348 1349 expr++; 1350 } 1351 1352 if (position != NULL) 1353 *position = expr; 1354 1355 do { 1356 if (currentExpr == NULL) 1357 continue; 1358 1359 ExpressionNode item; 1360 while (currentExpr->Pop(&item)) 1361 delete item.term; 1362 delete currentExpr; 1363 } while (exprsTree.Pop(¤tExpr)); 1364 1365 if (fTerm == NULL && status == B_OK) 1366 return B_BAD_VALUE; 1367 1368 QUERY_D(if (fTerm != NULL) { 1369 fTerm->PrintToStream(); 1370 QUERY_D(__out("\n")); 1371 if (*expr != '\0') 1372 PRINT(("Unexpected end of string: \"%s\"!\n", expr)); 1373 }); 1374 1375 return status; 1376 } 1377 1378 1379 template<typename QueryPolicy> 1380 Expression<QueryPolicy>::~Expression() 1381 { 1382 delete fTerm; 1383 } 1384 1385 1386 template<typename QueryPolicy> 1387 bool 1388 Expression<QueryPolicy>::IsOperator(const char** expr, char op) 1389 { 1390 const char* string = *expr; 1391 1392 if (*string == op && *(string + 1) == op) { 1393 *expr += 2; 1394 return true; 1395 } 1396 return false; 1397 } 1398 1399 1400 // #pragma mark - 1401 1402 1403 template<typename QueryPolicy> 1404 Query<QueryPolicy>::Query(Context* context, Expression<QueryPolicy>* expression, 1405 uint32 flags, port_id port, uint32 token) 1406 : 1407 fContext(context), 1408 fExpression(expression), 1409 fCurrent(NULL), 1410 fIterator(NULL), 1411 fIndex(context), 1412 fFlags(flags), 1413 fPort(port), 1414 fToken(token), 1415 fNeedsEntry(false) 1416 { 1417 // If the expression has a valid root pointer, the whole tree has 1418 // already passed the sanity check, so that we don't have to check 1419 // every pointer 1420 if (context == NULL || expression == NULL || expression->Root() == NULL) 1421 return; 1422 1423 // create index on the stack and delete it afterwards 1424 fExpression->Root()->CalculateScore(fIndex); 1425 QueryPolicy::IndexUnset(fIndex); 1426 1427 fNeedsEntry = fExpression->Root()->NeedsEntry(); 1428 1429 Rewind(); 1430 } 1431 1432 1433 template<typename QueryPolicy> 1434 Query<QueryPolicy>::~Query() 1435 { 1436 delete fExpression; 1437 } 1438 1439 1440 template<typename QueryPolicy> 1441 /*static*/ status_t 1442 Query<QueryPolicy>::Create(Context* context, const char* queryString, 1443 uint32 flags, port_id port, uint32 token, Query<QueryPolicy>*& _query) 1444 { 1445 Expression<QueryPolicy>* expression 1446 = new(std::nothrow) Expression<QueryPolicy>; 1447 if (expression == NULL) 1448 QUERY_RETURN_ERROR(B_NO_MEMORY); 1449 1450 const char* position = NULL; 1451 status_t status = expression->Init(queryString, &position); 1452 if (status != B_OK) { 1453 QUERY_INFORM("Could not parse query \"%s\", stopped at: \"%s\"\n", 1454 queryString, position); 1455 1456 delete expression; 1457 QUERY_RETURN_ERROR(status); 1458 } 1459 1460 Query<QueryPolicy>* query = new(std::nothrow) Query<QueryPolicy>(context, 1461 expression, flags, port, token); 1462 if (query == NULL) { 1463 delete expression; 1464 QUERY_RETURN_ERROR(B_NO_MEMORY); 1465 } 1466 1467 _query = query; 1468 return B_OK; 1469 } 1470 1471 1472 template<typename QueryPolicy> 1473 status_t 1474 Query<QueryPolicy>::Rewind() 1475 { 1476 // free previous stuff 1477 1478 fStack.MakeEmpty(); 1479 1480 QueryPolicy::IndexIteratorDelete(fIterator); 1481 fIterator = NULL; 1482 fCurrent = NULL; 1483 1484 // put the whole expression on the stack 1485 1486 Stack<Term<QueryPolicy>*> stack; 1487 stack.Push(fExpression->Root()); 1488 1489 Term<QueryPolicy>* term; 1490 while (stack.Pop(&term)) { 1491 if (term->Op() < OP_EQUATION) { 1492 Operator<QueryPolicy>* op = (Operator<QueryPolicy>*)term; 1493 1494 if (op->Op() == OP_OR) { 1495 stack.Push(op->Left()); 1496 stack.Push(op->Right()); 1497 } else { 1498 // For OP_AND, we can use the scoring system to decide which 1499 // path to add 1500 if (op->Right()->Score() > op->Left()->Score()) 1501 stack.Push(op->Right()); 1502 else 1503 stack.Push(op->Left()); 1504 } 1505 } else if (term->Op() == OP_EQUATION 1506 || fStack.Push((Equation<QueryPolicy>*)term) != B_OK) 1507 QUERY_FATAL("Unknown term on stack or stack error\n"); 1508 } 1509 1510 return B_OK; 1511 } 1512 1513 1514 template<typename QueryPolicy> 1515 status_t 1516 Query<QueryPolicy>::GetNextEntry(struct dirent* dirent, size_t size) 1517 { 1518 if (fIterator != NULL) 1519 QueryPolicy::IndexIteratorResume(fIterator); 1520 1521 status_t error = _GetNextEntry(dirent, size); 1522 1523 if (fIterator != NULL) 1524 QueryPolicy::IndexIteratorSuspend(fIterator); 1525 1526 return error; 1527 } 1528 1529 1530 template<typename QueryPolicy> 1531 void 1532 Query<QueryPolicy>::LiveUpdate(Entry* entry, Node* node, const char* attribute, 1533 int32 type, const uint8* oldKey, size_t oldLength, const uint8* newKey, 1534 size_t newLength) 1535 { 1536 if (fPort < 0 || fExpression == NULL || attribute == NULL) 1537 return; 1538 1539 // TODO: check if the attribute is part of the query at all... 1540 1541 // If no entry has been supplied, but the we need one for the evaluation 1542 // (i.e. the "name" attribute is used), we invoke ourselves for all entries 1543 // referring to the given node. 1544 if (entry == NULL && fNeedsEntry) { 1545 entry = QueryPolicy::NodeGetFirstReferrer(node); 1546 while (entry) { 1547 LiveUpdate(entry, node, attribute, type, oldKey, oldLength, newKey, 1548 newLength); 1549 entry = QueryPolicy::NodeGetNextReferrer(node, entry); 1550 } 1551 return; 1552 } 1553 1554 status_t oldStatus = fExpression->Root()->Match(entry, node, attribute, 1555 type, oldKey, oldLength); 1556 status_t newStatus = fExpression->Root()->Match(entry, node, attribute, 1557 type, newKey, newLength); 1558 1559 bool entryCreated = false; 1560 bool stillInQuery = false; 1561 1562 if (oldStatus != MATCH_OK) { 1563 if (newStatus != MATCH_OK) { 1564 // nothing has changed 1565 return; 1566 } 1567 entryCreated = true; 1568 } else if (newStatus != MATCH_OK) { 1569 // entry got removed 1570 entryCreated = false; 1571 } else if ((fFlags & B_ATTR_CHANGE_NOTIFICATION) != 0) { 1572 // The entry stays in the query 1573 stillInQuery = true; 1574 } else 1575 return; 1576 1577 // notify query listeners 1578 status_t (*notify)(port_id, int32, dev_t, ino_t, const char*, ino_t); 1579 1580 if (stillInQuery) 1581 notify = notify_query_attr_changed; 1582 else if (entryCreated) 1583 notify = notify_query_entry_created; 1584 else 1585 notify = notify_query_entry_removed; 1586 1587 if (entry != NULL) { 1588 _SendEntryNotification(entry, notify); 1589 } else { 1590 entry = QueryPolicy::NodeGetFirstReferrer(node); 1591 while (entry) { 1592 _SendEntryNotification(entry, notify); 1593 entry = QueryPolicy::NodeGetNextReferrer(node, entry); 1594 } 1595 } 1596 } 1597 1598 1599 template<typename QueryPolicy> 1600 void 1601 Query<QueryPolicy>::LiveUpdateRenameMove(Entry* entry, Node* node, 1602 ino_t oldDirectoryID, const char* oldName, size_t oldLength, 1603 ino_t newDirectoryID, const char* newName, size_t newLength) 1604 { 1605 if (fPort < 0 || fExpression == NULL) 1606 return; 1607 1608 // TODO: check if the attribute is part of the query at all... 1609 1610 status_t oldStatus = fExpression->Root()->Match(entry, node, "name", 1611 B_STRING_TYPE, (const uint8*)oldName, oldLength); 1612 status_t newStatus = fExpression->Root()->Match(entry, node, "name", 1613 B_STRING_TYPE, (const uint8*)newName, newLength); 1614 1615 if (oldStatus != MATCH_OK || oldStatus != newStatus) 1616 return; 1617 1618 // The entry stays in the query, notify query listeners about the rename 1619 // or move 1620 1621 // We send a notification for the given entry, if any, or otherwise for 1622 // all entries referring to the node; 1623 if (entry != NULL) { 1624 _SendEntryNotification(entry, notify_query_entry_removed); 1625 _SendEntryNotification(entry, notify_query_entry_created); 1626 } else { 1627 entry = QueryPolicy::NodeGetFirstReferrer(node); 1628 while (entry) { 1629 _SendEntryNotification(entry, notify_query_entry_removed); 1630 _SendEntryNotification(entry, notify_query_entry_created); 1631 entry = QueryPolicy::NodeGetNextReferrer(node, entry); 1632 } 1633 } 1634 } 1635 1636 1637 template<typename QueryPolicy> 1638 status_t 1639 Query<QueryPolicy>::_GetNextEntry(struct dirent* dirent, size_t size) 1640 { 1641 // If we don't have an equation to use yet/anymore, get a new one 1642 // from the stack 1643 while (true) { 1644 if (fIterator == NULL) { 1645 if (!fStack.Pop(&fCurrent) 1646 || fCurrent == NULL) 1647 return B_ENTRY_NOT_FOUND; 1648 1649 status_t status = fCurrent->PrepareQuery(fContext, fIndex, 1650 &fIterator, fFlags & B_QUERY_NON_INDEXED); 1651 if (status == B_ENTRY_NOT_FOUND) { 1652 // try next equation 1653 continue; 1654 } 1655 1656 if (status != B_OK) 1657 return status; 1658 } 1659 if (fCurrent == NULL) 1660 QUERY_RETURN_ERROR(B_ERROR); 1661 1662 status_t status = fCurrent->GetNextMatching(fContext, fIterator, dirent, 1663 size); 1664 if (status != B_OK) { 1665 QueryPolicy::IndexIteratorDelete(fIterator); 1666 fIterator = NULL; 1667 fCurrent = NULL; 1668 } else { 1669 // only return if we have another entry 1670 return B_OK; 1671 } 1672 } 1673 } 1674 1675 1676 template<typename QueryPolicy> 1677 void 1678 Query<QueryPolicy>::_SendEntryNotification(Entry* entry, 1679 status_t (*notify)(port_id, int32, dev_t, ino_t, const char*, ino_t)) 1680 { 1681 NodeHolder nodeHolder; 1682 const char* name = QueryPolicy::EntryGetNameNoCopy(nodeHolder, entry); 1683 if (name != NULL) { 1684 notify(fPort, fToken, QueryPolicy::ContextGetVolumeID(fContext), 1685 QueryPolicy::EntryGetParentID(entry), name, 1686 QueryPolicy::EntryGetNodeID(entry)); 1687 } 1688 } 1689 1690 1691 } // namespace QueryParser 1692 1693 1694 #endif // _FILE_SYSTEMS_QUERY_PARSER_H 1695