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