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_FATAL("query value conversion to 0x%x requested!\n", 634 (int)type); 635 // should we fail here or just do a safety int32 conversion? 636 return B_ERROR; 637 } 638 639 fType = type; 640 641 // patterns are only allowed for string types 642 if (fType != B_STRING_TYPE && fIsPattern) 643 fIsPattern = false; 644 645 return B_OK; 646 } 647 648 649 /*! Returns true when the key matches the equation. You have to 650 call ConvertValue() before this one. 651 */ 652 template<typename QueryPolicy> 653 bool 654 Equation<QueryPolicy>::CompareTo(const uint8* value, size_t size) 655 { 656 int32 compare; 657 658 // fIsPattern is only true if it's a string type, and fOp OP_EQUAL, or 659 // OP_UNEQUAL 660 if (fIsPattern) { 661 // we have already validated the pattern, so we don't check for failing 662 // here - if something is broken, and matchString() returns an error, 663 // we just don't match 664 compare = matchString(fValue.String, (const char*)value) == MATCH_OK ? 0 : 1; 665 } else 666 compare = compareKeys(fType, value, size, Value(), fSize); 667 668 switch (Term<QueryPolicy>::fOp) { 669 case OP_EQUAL: 670 return compare == 0; 671 case OP_UNEQUAL: 672 return compare != 0; 673 case OP_LESS_THAN: 674 return compare < 0; 675 case OP_LESS_THAN_OR_EQUAL: 676 return compare <= 0; 677 case OP_GREATER_THAN: 678 return compare > 0; 679 case OP_GREATER_THAN_OR_EQUAL: 680 return compare >= 0; 681 } 682 QUERY_FATAL("Unknown/Unsupported operation: %d\n", Term<QueryPolicy>::fOp); 683 return false; 684 } 685 686 687 template<typename QueryPolicy> 688 void 689 Equation<QueryPolicy>::Complement() 690 { 691 QUERY_D(if (Term<QueryPolicy>::fOp <= OP_EQUATION || Term<QueryPolicy>::fOp > OP_LESS_THAN_OR_EQUAL) { 692 QUERY_FATAL("op out of range!\n"); 693 return; 694 }); 695 696 int8 complementOp[] = {OP_UNEQUAL, OP_EQUAL, OP_LESS_THAN_OR_EQUAL, 697 OP_GREATER_THAN_OR_EQUAL, OP_LESS_THAN, OP_GREATER_THAN}; 698 Term<QueryPolicy>::fOp = complementOp[Term<QueryPolicy>::fOp - OP_EQUAL]; 699 } 700 701 702 /*! Matches the node's attribute value with the equation. 703 Returns MATCH_OK if it matches, NO_MATCH if not, < 0 if something went 704 wrong. 705 */ 706 template<typename QueryPolicy> 707 status_t 708 Equation<QueryPolicy>::Match(Entry* entry, Node* node, 709 const char* attributeName, int32 type, const uint8* key, size_t size) 710 { 711 // get a pointer to the attribute in question 712 NodeHolder nodeHolder; 713 union value<QueryPolicy> value; 714 uint8* buffer = (uint8*)&value; 715 const size_t bufferSize = sizeof(value); 716 717 // first, check if we are matching for a live query and use that value 718 if (attributeName != NULL && !strcmp(fAttribute, attributeName)) { 719 if (key == NULL) 720 return NO_MATCH; 721 buffer = const_cast<uint8*>(key); 722 } else if (!strcmp(fAttribute, "name")) { 723 // if not, check for "fake" attributes ("name", "size", "last_modified") 724 if (entry == NULL) 725 return B_ERROR; 726 buffer = (uint8*)QueryPolicy::EntryGetNameNoCopy(nodeHolder, entry); 727 if (buffer == NULL) 728 return B_ERROR; 729 730 type = B_STRING_TYPE; 731 size = strlen((const char*)buffer); 732 } else if (!strcmp(fAttribute, "size")) { 733 value.Int64 = QueryPolicy::NodeGetSize(node); 734 type = B_INT64_TYPE; 735 } else if (!strcmp(fAttribute, "last_modified")) { 736 value.Int64 = QueryPolicy::NodeGetLastModifiedTime(node); 737 type = B_INT64_TYPE; 738 } else { 739 // then for attributes 740 size = bufferSize; 741 if (QueryPolicy::NodeGetAttribute(nodeHolder, node, 742 fAttribute, buffer, &size, &type) != B_OK) { 743 return NO_MATCH; 744 } 745 } 746 747 // prepare own value for use, if it is possible to convert it 748 status_t status = ConvertValue(type); 749 if (status == B_OK) 750 status = CompareTo(buffer, size) ? MATCH_OK : NO_MATCH; 751 752 QUERY_RETURN_ERROR(status); 753 } 754 755 756 template<typename QueryPolicy> 757 void 758 Equation<QueryPolicy>::CalculateScore(Index &index) 759 { 760 // As always, these values could be tuned and refined. 761 // And the code could also need some real world testing :-) 762 763 // do we have to operate on a "foreign" index? 764 if (Term<QueryPolicy>::fOp == OP_UNEQUAL 765 || QueryPolicy::IndexSetTo(index, fAttribute) < B_OK) { 766 fScore = 0; 767 return; 768 } 769 770 // if we have a pattern, how much does it help our search? 771 if (fIsPattern) { 772 fScore = getFirstPatternSymbol(fString) << 3; 773 774 // Even if the first pattern symbol is at position 0, 775 // there's still an index, so don't let our score revert to zero. 776 if (fScore == 0) 777 fScore = 1; 778 } else { 779 // Score by operator 780 if (Term<QueryPolicy>::fOp == OP_EQUAL) { 781 // higher than pattern="255 chars+*" 782 fScore = 2048; 783 } else { 784 // the pattern search is regarded cheaper when you have at 785 // least one character to set your index to 786 fScore = 5; 787 } 788 } 789 790 // take index size into account 791 fScore = QueryPolicy::IndexGetWeightedScore(index, fScore); 792 } 793 794 795 template<typename QueryPolicy> 796 status_t 797 Equation<QueryPolicy>::PrepareQuery(Context* /*context*/, Index& index, 798 IndexIterator** iterator, bool queryNonIndexed) 799 { 800 status_t status = QueryPolicy::IndexSetTo(index, fAttribute); 801 802 // if we should query attributes without an index, we can just proceed here 803 if (status != B_OK && !queryNonIndexed) 804 return B_ENTRY_NOT_FOUND; 805 806 type_code type; 807 808 // Special case for OP_UNEQUAL - it will always operate through the whole 809 // index but we need the call to the original index to get the correct type 810 if (status != B_OK || Term<QueryPolicy>::fOp == OP_UNEQUAL) { 811 // Try to get an index that holds all files (name) 812 // Also sets the default type for all attributes without index 813 // to string. 814 type = status < B_OK ? B_STRING_TYPE : QueryPolicy::IndexGetType(index); 815 816 if (QueryPolicy::IndexSetTo(index, "name") != B_OK) 817 return B_ENTRY_NOT_FOUND; 818 819 fHasIndex = false; 820 } else { 821 fHasIndex = true; 822 type = QueryPolicy::IndexGetType(index); 823 } 824 825 if (ConvertValue(type) < B_OK) 826 return B_BAD_VALUE; 827 828 *iterator = QueryPolicy::IndexCreateIterator(index); 829 if (*iterator == NULL) 830 return B_NO_MEMORY; 831 832 if ((Term<QueryPolicy>::fOp == OP_EQUAL 833 || Term<QueryPolicy>::fOp == OP_GREATER_THAN 834 || Term<QueryPolicy>::fOp == OP_GREATER_THAN_OR_EQUAL || fIsPattern) 835 && fHasIndex) { 836 // set iterator to the exact position 837 838 int32 keySize = QueryPolicy::IndexGetKeySize(index); 839 840 // At this point, fIsPattern is only true if it's a string type, and fOp 841 // is either OP_EQUAL or OP_UNEQUAL 842 if (fIsPattern) { 843 // let's see if we can use the beginning of the key for positioning 844 // the iterator and adjust the key size; if not, just leave the 845 // iterator at the start and return success 846 keySize = getFirstPatternSymbol(fString); 847 if (keySize <= 0) 848 return B_OK; 849 } 850 851 if (keySize == 0) { 852 // B_STRING_TYPE doesn't have a fixed length, so it was set 853 // to 0 before - we compute the correct value here 854 if (fType == B_STRING_TYPE) { 855 keySize = strlen(fValue.String); 856 857 // The empty string is a special case - we normally don't check 858 // for the trailing null byte, in the case for the empty string 859 // we do it explicitly, because there can't be keys in the 860 // B+tree with a length of zero 861 if (keySize == 0) 862 keySize = 1; 863 } else 864 QUERY_RETURN_ERROR(B_ENTRY_NOT_FOUND); 865 } 866 867 status = QueryPolicy::IndexIteratorFind(*iterator, Value(), keySize); 868 if (Term<QueryPolicy>::fOp == OP_EQUAL && !fIsPattern) 869 return status; 870 else if (status == B_ENTRY_NOT_FOUND 871 && (fIsPattern || Term<QueryPolicy>::fOp == OP_GREATER_THAN 872 || Term<QueryPolicy>::fOp == OP_GREATER_THAN_OR_EQUAL)) 873 return B_OK; 874 875 QUERY_RETURN_ERROR(status); 876 } 877 878 return B_OK; 879 } 880 881 882 template<typename QueryPolicy> 883 status_t 884 Equation<QueryPolicy>::GetNextMatching(Context* context, 885 IndexIterator* iterator, struct dirent* dirent, size_t bufferSize) 886 { 887 while (true) { 888 NodeHolder nodeHolder; 889 union value<QueryPolicy> indexValue; 890 size_t keyLength; 891 size_t duplicate = 0; 892 893 status_t status = QueryPolicy::IndexIteratorFetchNextEntry(iterator, 894 &indexValue, &keyLength, (size_t)sizeof(indexValue), &duplicate); 895 if (status != B_OK) 896 return status; 897 898 // only compare against the index entry when this is the correct 899 // index for the equation 900 if (fHasIndex && duplicate < 2 && !CompareTo((uint8*)&indexValue, keyLength)) { 901 // They aren't equal? Let the operation decide what to do. Since 902 // we always start at the beginning of the index (or the correct 903 // position), only some needs to be stopped if the entry doesn't 904 // fit. 905 if (Term<QueryPolicy>::fOp == OP_LESS_THAN 906 || Term<QueryPolicy>::fOp == OP_LESS_THAN_OR_EQUAL 907 || (Term<QueryPolicy>::fOp == OP_EQUAL && !fIsPattern)) 908 return B_ENTRY_NOT_FOUND; 909 910 if (duplicate > 0) 911 QueryPolicy::IndexIteratorSkipDuplicates(iterator); 912 continue; 913 } 914 915 Entry* entry = NULL; 916 status = QueryPolicy::IndexIteratorGetEntry(context, iterator, 917 nodeHolder, &entry); 918 if (status != B_OK) { 919 // try with next 920 continue; 921 } 922 923 // TODO: check user permissions here - but which one?! 924 // we could filter out all those where we don't have 925 // read access... (we should check for every parent 926 // directory if the X_OK is allowed) 927 // Although it's quite expensive to open all parents, 928 // it's likely that the application that runs the 929 // query will do something similar (and we don't have 930 // to do it for root, either). 931 932 // go up in the tree until a &&-operator is found, and check if the 933 // node matches with the rest of the expression - we don't have to 934 // check ||-operators for that 935 Term<QueryPolicy>* term = this; 936 status = MATCH_OK; 937 938 if (!fHasIndex) 939 status = Match(entry, QueryPolicy::EntryGetNode(entry)); 940 941 while (term != NULL && status == MATCH_OK) { 942 Operator<QueryPolicy>* parent 943 = (Operator<QueryPolicy>*)term->Parent(); 944 if (parent == NULL) 945 break; 946 947 if (parent->Op() == OP_AND) { 948 // choose the other child of the parent 949 Term<QueryPolicy>* other = parent->Right(); 950 if (other == term) 951 other = parent->Left(); 952 953 if (other == NULL) { 954 QUERY_FATAL("&&-operator has only one child... " 955 "(parent = %p)\n", parent); 956 break; 957 } 958 status = other->Match(entry, QueryPolicy::EntryGetNode(entry)); 959 if (status < 0) { 960 QUERY_REPORT_ERROR(status); 961 status = NO_MATCH; 962 } 963 } 964 term = (Term<QueryPolicy>*)parent; 965 } 966 967 if (status == MATCH_OK) { 968 ssize_t nameLength = QueryPolicy::EntryGetName(entry, 969 dirent->d_name, 970 (const char*)dirent + bufferSize - dirent->d_name); 971 if (nameLength < 0) { 972 // Invalid or unknown name. 973 nameLength = 0; 974 } 975 976 dirent->d_dev = QueryPolicy::ContextGetVolumeID(context); 977 dirent->d_ino = QueryPolicy::EntryGetNodeID(entry); 978 dirent->d_pdev = dirent->d_dev; 979 dirent->d_pino = QueryPolicy::EntryGetParentID(entry); 980 dirent->d_reclen = offsetof(struct dirent, d_name) + nameLength; 981 } 982 983 if (status == MATCH_OK) 984 return B_OK; 985 } 986 QUERY_RETURN_ERROR(B_ERROR); 987 } 988 989 990 template<typename QueryPolicy> 991 bool 992 Equation<QueryPolicy>::NeedsEntry() 993 { 994 return strcmp(fAttribute, "name") == 0; 995 } 996 997 998 // #pragma mark - 999 1000 1001 template<typename QueryPolicy> 1002 Operator<QueryPolicy>::Operator(Term<QueryPolicy>* left, int8 op, 1003 Term<QueryPolicy>* right) 1004 : 1005 Term<QueryPolicy>(op), 1006 fLeft(left), 1007 fRight(right) 1008 { 1009 if (left) 1010 left->SetParent(this); 1011 if (right) 1012 right->SetParent(this); 1013 } 1014 1015 1016 template<typename QueryPolicy> 1017 Operator<QueryPolicy>::~Operator() 1018 { 1019 delete fLeft; 1020 delete fRight; 1021 } 1022 1023 1024 template<typename QueryPolicy> 1025 status_t 1026 Operator<QueryPolicy>::Match(Entry* entry, Node* node, const char* attribute, 1027 int32 type, const uint8* key, size_t size) 1028 { 1029 if (Term<QueryPolicy>::fOp == OP_AND) { 1030 status_t status = fLeft->Match(entry, node, attribute, type, key, 1031 size); 1032 if (status != MATCH_OK) 1033 return status; 1034 1035 return fRight->Match(entry, node, attribute, type, key, size); 1036 } else { 1037 // choose the term with the better score for OP_OR 1038 Term<QueryPolicy>* first; 1039 Term<QueryPolicy>* second; 1040 if (fRight->Score() > fLeft->Score()) { 1041 first = fLeft; 1042 second = fRight; 1043 } else { 1044 first = fRight; 1045 second = fLeft; 1046 } 1047 1048 status_t status = first->Match(entry, node, attribute, type, key, 1049 size); 1050 if (status != NO_MATCH) 1051 return status; 1052 1053 return second->Match(entry, node, attribute, type, key, size); 1054 } 1055 } 1056 1057 1058 template<typename QueryPolicy> 1059 void 1060 Operator<QueryPolicy>::Complement() 1061 { 1062 if (Term<QueryPolicy>::fOp == OP_AND) 1063 Term<QueryPolicy>::fOp = OP_OR; 1064 else 1065 Term<QueryPolicy>::fOp = OP_AND; 1066 1067 fLeft->Complement(); 1068 fRight->Complement(); 1069 } 1070 1071 1072 template<typename QueryPolicy> 1073 void 1074 Operator<QueryPolicy>::CalculateScore(Index &index) 1075 { 1076 fLeft->CalculateScore(index); 1077 fRight->CalculateScore(index); 1078 } 1079 1080 1081 template<typename QueryPolicy> 1082 int32 1083 Operator<QueryPolicy>::Score() const 1084 { 1085 if (Term<QueryPolicy>::fOp == OP_AND) { 1086 // return the one with the better score 1087 if (fRight->Score() > fLeft->Score()) 1088 return fRight->Score(); 1089 1090 return fLeft->Score(); 1091 } 1092 1093 // for OP_OR, be honest, and return the one with the worse score 1094 if (fRight->Score() < fLeft->Score()) 1095 return fRight->Score(); 1096 1097 return fLeft->Score(); 1098 } 1099 1100 1101 template<typename QueryPolicy> 1102 status_t 1103 Operator<QueryPolicy>::InitCheck() 1104 { 1105 if ((Term<QueryPolicy>::fOp != OP_AND && Term<QueryPolicy>::fOp != OP_OR) 1106 || fLeft == NULL || fLeft->InitCheck() < B_OK 1107 || fRight == NULL || fRight->InitCheck() < B_OK) 1108 return B_ERROR; 1109 1110 return B_OK; 1111 } 1112 1113 1114 template<typename QueryPolicy> 1115 bool 1116 Operator<QueryPolicy>::NeedsEntry() 1117 { 1118 return ((fLeft && fLeft->NeedsEntry()) || (fRight && fRight->NeedsEntry())); 1119 } 1120 1121 1122 // #pragma mark - 1123 1124 #ifdef DEBUG_QUERY 1125 1126 template<typename QueryPolicy> 1127 void 1128 Operator<QueryPolicy>::PrintToStream() 1129 { 1130 QUERY_D(__out("( ")); 1131 if (fLeft != NULL) 1132 fLeft->PrintToStream(); 1133 1134 const char* op; 1135 switch (Term<QueryPolicy>::fOp) { 1136 case OP_OR: op = "OR"; break; 1137 case OP_AND: op = "AND"; break; 1138 default: op = "?"; break; 1139 } 1140 QUERY_D(__out(" %s ", op)); 1141 1142 if (fRight != NULL) 1143 fRight->PrintToStream(); 1144 1145 QUERY_D(__out(" )")); 1146 } 1147 1148 1149 template<typename QueryPolicy> 1150 void 1151 Equation<QueryPolicy>::PrintToStream() 1152 { 1153 const char* symbol = "???"; 1154 switch (Term<QueryPolicy>::fOp) { 1155 case OP_EQUAL: symbol = "=="; break; 1156 case OP_UNEQUAL: symbol = "!="; break; 1157 case OP_GREATER_THAN: symbol = ">"; break; 1158 case OP_GREATER_THAN_OR_EQUAL: symbol = ">="; break; 1159 case OP_LESS_THAN: symbol = "<"; break; 1160 case OP_LESS_THAN_OR_EQUAL: symbol = "<="; break; 1161 } 1162 QUERY_D(__out("[\"%s\" %s \"%s\"]", fAttribute, symbol, fString)); 1163 } 1164 1165 #endif // DEBUG_QUERY 1166 1167 // #pragma mark - 1168 1169 1170 template<typename QueryPolicy> 1171 Expression<QueryPolicy>::Expression() 1172 : 1173 fTerm(NULL) 1174 { 1175 } 1176 1177 1178 template<typename QueryPolicy> 1179 status_t 1180 Expression<QueryPolicy>::Init(const char* expr, const char** position) 1181 { 1182 if (expr == NULL) 1183 return B_BAD_VALUE; 1184 if (fTerm != NULL) 1185 return EALREADY; 1186 1187 status_t status = B_OK; 1188 int32 equations = 0; 1189 const int32 kMaxEquations = 32; 1190 1191 struct ExpressionNode { 1192 Term<QueryPolicy>* term = NULL; 1193 bool negated = false; 1194 ops op = OP_NONE; 1195 }; 1196 Stack<Stack<ExpressionNode>*> exprsTree; 1197 Stack<ExpressionNode>* currentExpr = NULL; 1198 ExpressionNode* current = NULL; 1199 while (expr != NULL) { 1200 skipWhitespace(&expr); 1201 1202 if (currentExpr == NULL) { 1203 currentExpr = new(std::nothrow) Stack<ExpressionNode>; 1204 if (currentExpr == NULL) { 1205 status = B_NO_MEMORY; 1206 break; 1207 } 1208 } 1209 1210 const char c = *expr; 1211 bool complete = false; 1212 1213 if (c == ')' || c == '\0') { 1214 if (currentExpr->IsEmpty()) 1215 break; // Illegal empty expression. 1216 1217 complete = true; 1218 } 1219 1220 if (current == NULL && !complete) { 1221 currentExpr->Push(ExpressionNode()); 1222 current = currentExpr->Array() + (currentExpr->CountItems() - 1); 1223 } 1224 1225 if (c == '(') { 1226 exprsTree.Push(currentExpr); 1227 currentExpr = NULL; 1228 current = NULL; 1229 expr++; 1230 } else if (c == '!') { 1231 skipWhitespace(&expr, 1); 1232 if (*expr != '(') 1233 break; // Not allowed. 1234 current->negated = true; 1235 } else if (c == '|' || c == '&') { 1236 if (current->term == NULL) 1237 break; // Nothing to operate on. 1238 1239 ops op = OP_NONE; 1240 if (IsOperator(&expr, '|')) 1241 op = OP_OR; 1242 else if (IsOperator(&expr, '&')) 1243 op = OP_AND; 1244 else 1245 break; // Illegal operator. 1246 1247 current->op = op; 1248 current = NULL; 1249 } else if (!complete) { 1250 if (current->term != NULL) 1251 break; // There already is a term. 1252 if ((equations + 1) > kMaxEquations) { 1253 status = E2BIG; 1254 break; 1255 } 1256 1257 Equation<QueryPolicy>* equation 1258 = new(std::nothrow) Equation<QueryPolicy>(&expr); 1259 if (equation == NULL) { 1260 status = B_NO_MEMORY; 1261 break; 1262 } 1263 if (equation == NULL || equation->InitCheck() != B_OK) { 1264 status = equation->InitCheck(); 1265 delete equation; 1266 break; 1267 } 1268 1269 current->term = equation; 1270 equations++; 1271 } 1272 if (!complete) 1273 continue; 1274 1275 if (currentExpr->CountItems() == 1) { 1276 if (current == NULL) 1277 break; // Probably an anomalous operator. 1278 } 1279 1280 // First pass: negation. 1281 for (int32 i = 0; i < currentExpr->CountItems(); i++) { 1282 current = currentExpr->Array() + i; 1283 // If the term is negated, we just complement the tree, to get 1284 // rid of the not, a.k.a. DeMorgan's Law. 1285 if (current->negated) { 1286 current->term->Complement(); 1287 current->negated = false; 1288 } 1289 } 1290 // Second & third passes: && and ||. 1291 int32 nodes = currentExpr->CountItems(); 1292 for (ops op = OP_AND; op <= OP_OR; op = (ops)(op + 1)) { 1293 for (int32 i = 0; i < (currentExpr->CountItems() - 1); ) { 1294 ExpressionNode* left = currentExpr->Array() + i; 1295 if (left->op != op) { 1296 i++; 1297 continue; 1298 } 1299 1300 // Find the right-hand expression (may have to jump over now-unused nodes.) 1301 ExpressionNode* right = NULL; 1302 for (int32 j = i + 1; j < currentExpr->CountItems(); j++) { 1303 current = currentExpr->Array() + j; 1304 if (current->term == NULL) 1305 continue; 1306 1307 right = current; 1308 break; 1309 } 1310 if (right == NULL) 1311 break; // Invalid expression, somehow. 1312 1313 Term<QueryPolicy>* newTerm = new(std::nothrow) Operator<QueryPolicy>( 1314 left->term, left->op, right->term); 1315 if (newTerm == NULL) { 1316 status = B_NO_MEMORY; 1317 break; 1318 } 1319 1320 left->term = newTerm; 1321 left->op = right->op; 1322 right->op = OP_NONE; 1323 right->term = NULL; 1324 nodes--; 1325 } 1326 } 1327 1328 // At this point we should have only one node left. 1329 if (nodes != 1) 1330 break; 1331 1332 current = currentExpr->Array(); 1333 Term<QueryPolicy>* term = current->term; 1334 1335 delete currentExpr; 1336 currentExpr = NULL; 1337 if (exprsTree.Pop(¤tExpr)) { 1338 current = currentExpr->Array() + (currentExpr->CountItems() - 1); 1339 if (current->term != NULL) 1340 break; // There already is a term. 1341 current->term = term; 1342 } else { 1343 if (c != '\0') 1344 break; // Unexpected end of expression. 1345 1346 fTerm = term; 1347 break; 1348 } 1349 1350 expr++; 1351 } 1352 1353 if (position != NULL) 1354 *position = expr; 1355 1356 do { 1357 if (currentExpr == NULL) 1358 continue; 1359 1360 ExpressionNode item; 1361 while (currentExpr->Pop(&item)) 1362 delete item.term; 1363 delete currentExpr; 1364 } while (exprsTree.Pop(¤tExpr)); 1365 1366 if (fTerm == NULL && status == B_OK) 1367 return B_BAD_VALUE; 1368 1369 QUERY_D(if (fTerm != NULL) { 1370 fTerm->PrintToStream(); 1371 QUERY_D(__out("\n")); 1372 if (*expr != '\0') 1373 PRINT(("Unexpected end of string: \"%s\"!\n", expr)); 1374 }); 1375 1376 return status; 1377 } 1378 1379 1380 template<typename QueryPolicy> 1381 Expression<QueryPolicy>::~Expression() 1382 { 1383 delete fTerm; 1384 } 1385 1386 1387 template<typename QueryPolicy> 1388 bool 1389 Expression<QueryPolicy>::IsOperator(const char** expr, char op) 1390 { 1391 const char* string = *expr; 1392 1393 if (*string == op && *(string + 1) == op) { 1394 *expr += 2; 1395 return true; 1396 } 1397 return false; 1398 } 1399 1400 1401 // #pragma mark - 1402 1403 1404 template<typename QueryPolicy> 1405 Query<QueryPolicy>::Query(Context* context, Expression<QueryPolicy>* expression, 1406 uint32 flags, port_id port, uint32 token) 1407 : 1408 fContext(context), 1409 fExpression(expression), 1410 fCurrent(NULL), 1411 fIterator(NULL), 1412 fIndex(context), 1413 fFlags(flags), 1414 fPort(port), 1415 fToken(token), 1416 fNeedsEntry(false) 1417 { 1418 // If the expression has a valid root pointer, the whole tree has 1419 // already passed the sanity check, so that we don't have to check 1420 // every pointer 1421 if (context == NULL || expression == NULL || expression->Root() == NULL) 1422 return; 1423 1424 // create index on the stack and delete it afterwards 1425 fExpression->Root()->CalculateScore(fIndex); 1426 QueryPolicy::IndexUnset(fIndex); 1427 1428 fNeedsEntry = fExpression->Root()->NeedsEntry(); 1429 1430 Rewind(); 1431 } 1432 1433 1434 template<typename QueryPolicy> 1435 Query<QueryPolicy>::~Query() 1436 { 1437 delete fExpression; 1438 } 1439 1440 1441 template<typename QueryPolicy> 1442 /*static*/ status_t 1443 Query<QueryPolicy>::Create(Context* context, const char* queryString, 1444 uint32 flags, port_id port, uint32 token, Query<QueryPolicy>*& _query) 1445 { 1446 Expression<QueryPolicy>* expression 1447 = new(std::nothrow) Expression<QueryPolicy>; 1448 if (expression == NULL) 1449 QUERY_RETURN_ERROR(B_NO_MEMORY); 1450 1451 const char* position = NULL; 1452 status_t status = expression->Init(queryString, &position); 1453 if (status != B_OK) { 1454 QUERY_INFORM("Could not parse query \"%s\", stopped at: \"%s\"\n", 1455 queryString, position); 1456 1457 delete expression; 1458 QUERY_RETURN_ERROR(status); 1459 } 1460 1461 Query<QueryPolicy>* query = new(std::nothrow) Query<QueryPolicy>(context, 1462 expression, flags, port, token); 1463 if (query == NULL) { 1464 delete expression; 1465 QUERY_RETURN_ERROR(B_NO_MEMORY); 1466 } 1467 1468 _query = query; 1469 return B_OK; 1470 } 1471 1472 1473 template<typename QueryPolicy> 1474 status_t 1475 Query<QueryPolicy>::Rewind() 1476 { 1477 // free previous stuff 1478 1479 fStack.MakeEmpty(); 1480 1481 QueryPolicy::IndexIteratorDelete(fIterator); 1482 fIterator = NULL; 1483 fCurrent = NULL; 1484 1485 // put the whole expression on the stack 1486 1487 Stack<Term<QueryPolicy>*> stack; 1488 stack.Push(fExpression->Root()); 1489 1490 Term<QueryPolicy>* term; 1491 while (stack.Pop(&term)) { 1492 if (term->Op() < OP_EQUATION) { 1493 Operator<QueryPolicy>* op = (Operator<QueryPolicy>*)term; 1494 1495 if (op->Op() == OP_OR) { 1496 stack.Push(op->Left()); 1497 stack.Push(op->Right()); 1498 } else { 1499 // For OP_AND, we can use the scoring system to decide which 1500 // path to add 1501 if (op->Right()->Score() > op->Left()->Score()) 1502 stack.Push(op->Right()); 1503 else 1504 stack.Push(op->Left()); 1505 } 1506 } else if (term->Op() == OP_EQUATION 1507 || fStack.Push((Equation<QueryPolicy>*)term) != B_OK) 1508 QUERY_FATAL("Unknown term on stack or stack error\n"); 1509 } 1510 1511 return B_OK; 1512 } 1513 1514 1515 template<typename QueryPolicy> 1516 status_t 1517 Query<QueryPolicy>::GetNextEntry(struct dirent* dirent, size_t size) 1518 { 1519 if (fIterator != NULL) 1520 QueryPolicy::IndexIteratorResume(fIterator); 1521 1522 status_t error = _GetNextEntry(dirent, size); 1523 1524 if (fIterator != NULL) 1525 QueryPolicy::IndexIteratorSuspend(fIterator); 1526 1527 return error; 1528 } 1529 1530 1531 template<typename QueryPolicy> 1532 void 1533 Query<QueryPolicy>::LiveUpdate(Entry* entry, Node* node, const char* attribute, 1534 int32 type, const uint8* oldKey, size_t oldLength, const uint8* newKey, 1535 size_t newLength) 1536 { 1537 if (fPort < 0 || fExpression == NULL || attribute == NULL) 1538 return; 1539 1540 // TODO: check if the attribute is part of the query at all... 1541 1542 // If no entry has been supplied, but the we need one for the evaluation 1543 // (i.e. the "name" attribute is used), we invoke ourselves for all entries 1544 // referring to the given node. 1545 if (entry == NULL && fNeedsEntry) { 1546 entry = QueryPolicy::NodeGetFirstReferrer(node); 1547 while (entry) { 1548 LiveUpdate(entry, node, attribute, type, oldKey, oldLength, newKey, 1549 newLength); 1550 entry = QueryPolicy::NodeGetNextReferrer(node, entry); 1551 } 1552 return; 1553 } 1554 1555 status_t oldStatus = fExpression->Root()->Match(entry, node, attribute, 1556 type, oldKey, oldLength); 1557 status_t newStatus = fExpression->Root()->Match(entry, node, attribute, 1558 type, newKey, newLength); 1559 1560 bool entryCreated = false; 1561 bool stillInQuery = false; 1562 1563 if (oldStatus != MATCH_OK) { 1564 if (newStatus != MATCH_OK) { 1565 // nothing has changed 1566 return; 1567 } 1568 entryCreated = true; 1569 } else if (newStatus != MATCH_OK) { 1570 // entry got removed 1571 entryCreated = false; 1572 } else if ((fFlags & B_ATTR_CHANGE_NOTIFICATION) != 0) { 1573 // The entry stays in the query 1574 stillInQuery = true; 1575 } else 1576 return; 1577 1578 // notify query listeners 1579 status_t (*notify)(port_id, int32, dev_t, ino_t, const char*, ino_t); 1580 1581 if (stillInQuery) 1582 notify = notify_query_attr_changed; 1583 else if (entryCreated) 1584 notify = notify_query_entry_created; 1585 else 1586 notify = notify_query_entry_removed; 1587 1588 if (entry != NULL) { 1589 _SendEntryNotification(entry, notify); 1590 } else { 1591 entry = QueryPolicy::NodeGetFirstReferrer(node); 1592 while (entry) { 1593 _SendEntryNotification(entry, notify); 1594 entry = QueryPolicy::NodeGetNextReferrer(node, entry); 1595 } 1596 } 1597 } 1598 1599 1600 template<typename QueryPolicy> 1601 void 1602 Query<QueryPolicy>::LiveUpdateRenameMove(Entry* entry, Node* node, 1603 ino_t oldDirectoryID, const char* oldName, size_t oldLength, 1604 ino_t newDirectoryID, const char* newName, size_t newLength) 1605 { 1606 if (fPort < 0 || fExpression == NULL) 1607 return; 1608 1609 // TODO: check if the attribute is part of the query at all... 1610 1611 status_t oldStatus = fExpression->Root()->Match(entry, node, "name", 1612 B_STRING_TYPE, (const uint8*)oldName, oldLength); 1613 status_t newStatus = fExpression->Root()->Match(entry, node, "name", 1614 B_STRING_TYPE, (const uint8*)newName, newLength); 1615 1616 if (oldStatus != MATCH_OK || oldStatus != newStatus) 1617 return; 1618 1619 // The entry stays in the query, notify query listeners about the rename 1620 // or move 1621 1622 // We send a notification for the given entry, if any, or otherwise for 1623 // all entries referring to the node; 1624 if (entry != NULL) { 1625 _SendEntryNotification(entry, notify_query_entry_removed); 1626 _SendEntryNotification(entry, notify_query_entry_created); 1627 } else { 1628 entry = QueryPolicy::NodeGetFirstReferrer(node); 1629 while (entry) { 1630 _SendEntryNotification(entry, notify_query_entry_removed); 1631 _SendEntryNotification(entry, notify_query_entry_created); 1632 entry = QueryPolicy::NodeGetNextReferrer(node, entry); 1633 } 1634 } 1635 } 1636 1637 1638 template<typename QueryPolicy> 1639 status_t 1640 Query<QueryPolicy>::_GetNextEntry(struct dirent* dirent, size_t size) 1641 { 1642 // If we don't have an equation to use yet/anymore, get a new one 1643 // from the stack 1644 while (true) { 1645 if (fIterator == NULL) { 1646 if (!fStack.Pop(&fCurrent) 1647 || fCurrent == NULL) 1648 return B_ENTRY_NOT_FOUND; 1649 1650 status_t status = fCurrent->PrepareQuery(fContext, fIndex, 1651 &fIterator, fFlags & B_QUERY_NON_INDEXED); 1652 if (status == B_ENTRY_NOT_FOUND) { 1653 // try next equation 1654 continue; 1655 } 1656 1657 if (status != B_OK) 1658 return status; 1659 } 1660 if (fCurrent == NULL) 1661 QUERY_RETURN_ERROR(B_ERROR); 1662 1663 status_t status = fCurrent->GetNextMatching(fContext, fIterator, dirent, 1664 size); 1665 if (status != B_OK) { 1666 QueryPolicy::IndexIteratorDelete(fIterator); 1667 fIterator = NULL; 1668 fCurrent = NULL; 1669 } else { 1670 // only return if we have another entry 1671 return B_OK; 1672 } 1673 } 1674 } 1675 1676 1677 template<typename QueryPolicy> 1678 void 1679 Query<QueryPolicy>::_SendEntryNotification(Entry* entry, 1680 status_t (*notify)(port_id, int32, dev_t, ino_t, const char*, ino_t)) 1681 { 1682 NodeHolder nodeHolder; 1683 const char* name = QueryPolicy::EntryGetNameNoCopy(nodeHolder, entry); 1684 if (name != NULL) { 1685 notify(fPort, fToken, QueryPolicy::ContextGetVolumeID(fContext), 1686 QueryPolicy::EntryGetParentID(entry), name, 1687 QueryPolicy::EntryGetNodeID(entry)); 1688 } 1689 } 1690 1691 1692 } // namespace QueryParser 1693 1694 1695 #endif // _FILE_SYSTEMS_QUERY_PARSER_H 1696