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 712 // first, check if we are matching for a live query and use that value 713 if (attributeName != NULL && !strcmp(fAttribute, attributeName)) { 714 if (key == NULL) { 715 if (type == B_STRING_TYPE) 716 return MatchEmptyString(); 717 718 return NO_MATCH; 719 } 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(entry, buffer, 726 sizeof(value)); 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.Int32 = QueryPolicy::NodeGetLastModifiedTime(node); 737 type = B_INT32_TYPE; 738 } else { 739 // then for attributes 740 if (QueryPolicy::NodeGetAttribute(node, fAttribute, buffer, &size, 741 &type) != B_OK) { 742 return MatchEmptyString(); 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 else { 773 // Score by operator 774 if (Term<QueryPolicy>::fOp == OP_EQUAL) { 775 // higher than pattern="255 chars+*" 776 fScore = 2048; 777 } else { 778 // the pattern search is regarded cheaper when you have at 779 // least one character to set your index to 780 fScore = 5; 781 } 782 } 783 784 // take index size into account 785 fScore = QueryPolicy::IndexGetWeightedScore(index, fScore); 786 } 787 788 789 template<typename QueryPolicy> 790 status_t 791 Equation<QueryPolicy>::PrepareQuery(Context* /*context*/, Index& index, 792 IndexIterator** iterator, bool queryNonIndexed) 793 { 794 status_t status = QueryPolicy::IndexSetTo(index, fAttribute); 795 796 // if we should query attributes without an index, we can just proceed here 797 if (status != B_OK && !queryNonIndexed) 798 return B_ENTRY_NOT_FOUND; 799 800 type_code type; 801 802 // Special case for OP_UNEQUAL - it will always operate through the whole 803 // index but we need the call to the original index to get the correct type 804 if (status != B_OK || Term<QueryPolicy>::fOp == OP_UNEQUAL) { 805 // Try to get an index that holds all files (name) 806 // Also sets the default type for all attributes without index 807 // to string. 808 type = status < B_OK ? B_STRING_TYPE : QueryPolicy::IndexGetType(index); 809 810 if (QueryPolicy::IndexSetTo(index, "name") != B_OK) 811 return B_ENTRY_NOT_FOUND; 812 813 fHasIndex = false; 814 } else { 815 fHasIndex = true; 816 type = QueryPolicy::IndexGetType(index); 817 } 818 819 if (ConvertValue(type) < B_OK) 820 return B_BAD_VALUE; 821 822 *iterator = QueryPolicy::IndexCreateIterator(index); 823 if (*iterator == NULL) 824 return B_NO_MEMORY; 825 826 if ((Term<QueryPolicy>::fOp == OP_EQUAL 827 || Term<QueryPolicy>::fOp == OP_GREATER_THAN 828 || Term<QueryPolicy>::fOp == OP_GREATER_THAN_OR_EQUAL || fIsPattern) 829 && fHasIndex) { 830 // set iterator to the exact position 831 832 int32 keySize = QueryPolicy::IndexGetKeySize(index); 833 834 // At this point, fIsPattern is only true if it's a string type, and fOp 835 // is either OP_EQUAL or OP_UNEQUAL 836 if (fIsPattern) { 837 // let's see if we can use the beginning of the key for positioning 838 // the iterator and adjust the key size; if not, just leave the 839 // iterator at the start and return success 840 keySize = getFirstPatternSymbol(fString); 841 if (keySize <= 0) 842 return B_OK; 843 } 844 845 if (keySize == 0) { 846 // B_STRING_TYPE doesn't have a fixed length, so it was set 847 // to 0 before - we compute the correct value here 848 if (fType == B_STRING_TYPE) { 849 keySize = strlen(fValue.String); 850 851 // The empty string is a special case - we normally don't check 852 // for the trailing null byte, in the case for the empty string 853 // we do it explicitly, because there can't be keys in the 854 // B+tree with a length of zero 855 if (keySize == 0) 856 keySize = 1; 857 } else 858 QUERY_RETURN_ERROR(B_ENTRY_NOT_FOUND); 859 } 860 861 status = QueryPolicy::IndexIteratorFind(*iterator, Value(), keySize); 862 if (Term<QueryPolicy>::fOp == OP_EQUAL && !fIsPattern) 863 return status; 864 else if (status == B_ENTRY_NOT_FOUND 865 && (fIsPattern || Term<QueryPolicy>::fOp == OP_GREATER_THAN 866 || Term<QueryPolicy>::fOp == OP_GREATER_THAN_OR_EQUAL)) 867 return B_OK; 868 869 QUERY_RETURN_ERROR(status); 870 } 871 872 return B_OK; 873 } 874 875 876 template<typename QueryPolicy> 877 status_t 878 Equation<QueryPolicy>::GetNextMatching(Context* context, 879 IndexIterator* iterator, struct dirent* dirent, size_t bufferSize) 880 { 881 while (true) { 882 union value<QueryPolicy> indexValue; 883 size_t keyLength; 884 Entry* entry = NULL; 885 886 status_t status = QueryPolicy::IndexIteratorGetNextEntry(iterator, 887 &indexValue, &keyLength, (size_t)sizeof(indexValue), &entry); 888 if (status != B_OK) 889 return status; 890 891 // only compare against the index entry when this is the correct 892 // index for the equation 893 if (fHasIndex && !CompareTo((uint8*)&indexValue, keyLength)) { 894 // They aren't equal? Let the operation decide what to do. Since 895 // we always start at the beginning of the index (or the correct 896 // position), only some needs to be stopped if the entry doesn't 897 // fit. 898 if (Term<QueryPolicy>::fOp == OP_LESS_THAN 899 || Term<QueryPolicy>::fOp == OP_LESS_THAN_OR_EQUAL 900 || (Term<QueryPolicy>::fOp == OP_EQUAL && !fIsPattern)) 901 return B_ENTRY_NOT_FOUND; 902 903 continue; 904 } 905 906 // TODO: check user permissions here - but which one?! 907 // we could filter out all those where we don't have 908 // read access... (we should check for every parent 909 // directory if the X_OK is allowed) 910 // Although it's quite expensive to open all parents, 911 // it's likely that the application that runs the 912 // query will do something similar (and we don't have 913 // to do it for root, either). 914 915 // go up in the tree until a &&-operator is found, and check if the 916 // node matches with the rest of the expression - we don't have to 917 // check ||-operators for that 918 Term<QueryPolicy>* term = this; 919 status = MATCH_OK; 920 921 if (!fHasIndex) 922 status = Match(entry, QueryPolicy::EntryGetNode(entry)); 923 924 while (term != NULL && status == MATCH_OK) { 925 Operator<QueryPolicy>* parent 926 = (Operator<QueryPolicy>*)term->Parent(); 927 if (parent == NULL) 928 break; 929 930 if (parent->Op() == OP_AND) { 931 // choose the other child of the parent 932 Term<QueryPolicy>* other = parent->Right(); 933 if (other == term) 934 other = parent->Left(); 935 936 if (other == NULL) { 937 QUERY_FATAL("&&-operator has only one child... " 938 "(parent = %p)\n", parent); 939 break; 940 } 941 status = other->Match(entry, QueryPolicy::EntryGetNode(entry)); 942 if (status < 0) { 943 QUERY_REPORT_ERROR(status); 944 status = NO_MATCH; 945 } 946 } 947 term = (Term<QueryPolicy>*)parent; 948 } 949 950 if (status == MATCH_OK) { 951 ssize_t nameLength = QueryPolicy::EntryGetName(entry, 952 dirent->d_name, 953 (const char*)dirent + bufferSize - dirent->d_name); 954 if (nameLength < 0) 955 QUERY_RETURN_ERROR(nameLength); 956 957 dirent->d_dev = QueryPolicy::ContextGetVolumeID(context); 958 dirent->d_ino = QueryPolicy::EntryGetNodeID(entry); 959 dirent->d_pdev = dirent->d_dev; 960 dirent->d_pino = QueryPolicy::EntryGetParentID(entry); 961 dirent->d_reclen = sizeof(struct dirent) + strlen(dirent->d_name); 962 } 963 964 if (status == MATCH_OK) 965 return B_OK; 966 } 967 QUERY_RETURN_ERROR(B_ERROR); 968 } 969 970 971 template<typename QueryPolicy> 972 bool 973 Equation<QueryPolicy>::NeedsEntry() 974 { 975 return strcmp(fAttribute, "name") == 0; 976 } 977 978 979 // #pragma mark - 980 981 982 template<typename QueryPolicy> 983 Operator<QueryPolicy>::Operator(Term<QueryPolicy>* left, int8 op, 984 Term<QueryPolicy>* right) 985 : 986 Term<QueryPolicy>(op), 987 fLeft(left), 988 fRight(right) 989 { 990 if (left) 991 left->SetParent(this); 992 if (right) 993 right->SetParent(this); 994 } 995 996 997 template<typename QueryPolicy> 998 Operator<QueryPolicy>::~Operator() 999 { 1000 delete fLeft; 1001 delete fRight; 1002 } 1003 1004 1005 template<typename QueryPolicy> 1006 status_t 1007 Operator<QueryPolicy>::Match(Entry* entry, Node* node, const char* attribute, 1008 int32 type, const uint8* key, size_t size) 1009 { 1010 if (Term<QueryPolicy>::fOp == OP_AND) { 1011 status_t status = fLeft->Match(entry, node, attribute, type, key, 1012 size); 1013 if (status != MATCH_OK) 1014 return status; 1015 1016 return fRight->Match(entry, node, attribute, type, key, size); 1017 } else { 1018 // choose the term with the better score for OP_OR 1019 Term<QueryPolicy>* first; 1020 Term<QueryPolicy>* second; 1021 if (fRight->Score() > fLeft->Score()) { 1022 first = fLeft; 1023 second = fRight; 1024 } else { 1025 first = fRight; 1026 second = fLeft; 1027 } 1028 1029 status_t status = first->Match(entry, node, attribute, type, key, 1030 size); 1031 if (status != NO_MATCH) 1032 return status; 1033 1034 return second->Match(entry, node, attribute, type, key, size); 1035 } 1036 } 1037 1038 1039 template<typename QueryPolicy> 1040 void 1041 Operator<QueryPolicy>::Complement() 1042 { 1043 if (Term<QueryPolicy>::fOp == OP_AND) 1044 Term<QueryPolicy>::fOp = OP_OR; 1045 else 1046 Term<QueryPolicy>::fOp = OP_AND; 1047 1048 fLeft->Complement(); 1049 fRight->Complement(); 1050 } 1051 1052 1053 template<typename QueryPolicy> 1054 void 1055 Operator<QueryPolicy>::CalculateScore(Index &index) 1056 { 1057 fLeft->CalculateScore(index); 1058 fRight->CalculateScore(index); 1059 } 1060 1061 1062 template<typename QueryPolicy> 1063 int32 1064 Operator<QueryPolicy>::Score() const 1065 { 1066 if (Term<QueryPolicy>::fOp == OP_AND) { 1067 // return the one with the better score 1068 if (fRight->Score() > fLeft->Score()) 1069 return fRight->Score(); 1070 1071 return fLeft->Score(); 1072 } 1073 1074 // for OP_OR, be honest, and return the one with the worse score 1075 if (fRight->Score() < fLeft->Score()) 1076 return fRight->Score(); 1077 1078 return fLeft->Score(); 1079 } 1080 1081 1082 template<typename QueryPolicy> 1083 status_t 1084 Operator<QueryPolicy>::InitCheck() 1085 { 1086 if ((Term<QueryPolicy>::fOp != OP_AND && Term<QueryPolicy>::fOp != OP_OR) 1087 || fLeft == NULL || fLeft->InitCheck() < B_OK 1088 || fRight == NULL || fRight->InitCheck() < B_OK) 1089 return B_ERROR; 1090 1091 return B_OK; 1092 } 1093 1094 1095 template<typename QueryPolicy> 1096 bool 1097 Operator<QueryPolicy>::NeedsEntry() 1098 { 1099 return ((fLeft && fLeft->NeedsEntry()) || (fRight && fRight->NeedsEntry())); 1100 } 1101 1102 1103 // #pragma mark - 1104 1105 #ifdef DEBUG_QUERY 1106 1107 template<typename QueryPolicy> 1108 void 1109 Operator<QueryPolicy>::PrintToStream() 1110 { 1111 D(__out("( ")); 1112 if (fLeft != NULL) 1113 fLeft->PrintToStream(); 1114 1115 const char* op; 1116 switch (Term<QueryPolicy>::fOp) { 1117 case OP_OR: op = "OR"; break; 1118 case OP_AND: op = "AND"; break; 1119 default: op = "?"; break; 1120 } 1121 D(__out(" %s ", op)); 1122 1123 if (fRight != NULL) 1124 fRight->PrintToStream(); 1125 1126 D(__out(" )")); 1127 } 1128 1129 1130 template<typename QueryPolicy> 1131 void 1132 Equation<QueryPolicy>::PrintToStream() 1133 { 1134 const char* symbol = "???"; 1135 switch (Term<QueryPolicy>::fOp) { 1136 case OP_EQUAL: symbol = "=="; break; 1137 case OP_UNEQUAL: symbol = "!="; break; 1138 case OP_GREATER_THAN: symbol = ">"; break; 1139 case OP_GREATER_THAN_OR_EQUAL: symbol = ">="; break; 1140 case OP_LESS_THAN: symbol = "<"; break; 1141 case OP_LESS_THAN_OR_EQUAL: symbol = "<="; break; 1142 } 1143 D(__out("[\"%s\" %s \"%s\"]", fAttribute, symbol, fString)); 1144 } 1145 1146 #endif // DEBUG_QUERY 1147 1148 // #pragma mark - 1149 1150 1151 template<typename QueryPolicy> 1152 Expression<QueryPolicy>::Expression(char* expr) 1153 { 1154 if (expr == NULL) 1155 return; 1156 1157 fTerm = ParseOr(&expr); 1158 if (fTerm != NULL && fTerm->InitCheck() < B_OK) { 1159 QUERY_FATAL("Corrupt tree in expression!\n"); 1160 delete fTerm; 1161 fTerm = NULL; 1162 } 1163 QUERY_D(if (fTerm != NULL) { 1164 fTerm->PrintToStream(); 1165 D(__out("\n")); 1166 if (*expr != '\0') 1167 PRINT(("Unexpected end of string: \"%s\"!\n", expr)); 1168 }); 1169 fPosition = expr; 1170 } 1171 1172 1173 template<typename QueryPolicy> 1174 Expression<QueryPolicy>::~Expression() 1175 { 1176 delete fTerm; 1177 } 1178 1179 1180 template<typename QueryPolicy> 1181 Term<QueryPolicy>* 1182 Expression<QueryPolicy>::ParseEquation(char** expr) 1183 { 1184 skipWhitespace(expr); 1185 1186 bool _not = false; 1187 if (**expr == '!') { 1188 skipWhitespace(expr, 1); 1189 if (**expr != '(') 1190 return NULL; 1191 1192 _not = true; 1193 } 1194 1195 if (**expr == ')') { 1196 // shouldn't be handled here 1197 return NULL; 1198 } else if (**expr == '(') { 1199 skipWhitespace(expr, 1); 1200 1201 Term<QueryPolicy>* term = ParseOr(expr); 1202 1203 skipWhitespace(expr); 1204 1205 if (**expr != ')') { 1206 delete term; 1207 return NULL; 1208 } 1209 1210 // If the term is negated, we just complement the tree, to get 1211 // rid of the not, a.k.a. DeMorgan's Law. 1212 if (_not) 1213 term->Complement(); 1214 1215 skipWhitespace(expr, 1); 1216 1217 return term; 1218 } 1219 1220 Equation<QueryPolicy>* equation 1221 = new(std::nothrow) Equation<QueryPolicy>(expr); 1222 if (equation == NULL || equation->InitCheck() < B_OK) { 1223 delete equation; 1224 return NULL; 1225 } 1226 return equation; 1227 } 1228 1229 1230 template<typename QueryPolicy> 1231 Term<QueryPolicy>* 1232 Expression<QueryPolicy>::ParseAnd(char** expr) 1233 { 1234 Term<QueryPolicy>* left = ParseEquation(expr); 1235 if (left == NULL) 1236 return NULL; 1237 1238 while (IsOperator(expr, '&')) { 1239 Term<QueryPolicy>* right = ParseAnd(expr); 1240 Term<QueryPolicy>* newParent = NULL; 1241 1242 if (right == NULL 1243 || (newParent = new(std::nothrow) Operator<QueryPolicy>(left, 1244 OP_AND, right)) == NULL) { 1245 delete left; 1246 delete right; 1247 1248 return NULL; 1249 } 1250 left = newParent; 1251 } 1252 1253 return left; 1254 } 1255 1256 1257 template<typename QueryPolicy> 1258 Term<QueryPolicy>* 1259 Expression<QueryPolicy>::ParseOr(char** expr) 1260 { 1261 Term<QueryPolicy>* left = ParseAnd(expr); 1262 if (left == NULL) 1263 return NULL; 1264 1265 while (IsOperator(expr, '|')) { 1266 Term<QueryPolicy>* right = ParseAnd(expr); 1267 Term<QueryPolicy>* newParent = NULL; 1268 1269 if (right == NULL 1270 || (newParent = new(std::nothrow) Operator<QueryPolicy>(left, OP_OR, 1271 right)) == NULL) { 1272 delete left; 1273 delete right; 1274 1275 return NULL; 1276 } 1277 left = newParent; 1278 } 1279 1280 return left; 1281 } 1282 1283 1284 template<typename QueryPolicy> 1285 bool 1286 Expression<QueryPolicy>::IsOperator(char** expr, char op) 1287 { 1288 char* string = *expr; 1289 1290 if (*string == op && *(string + 1) == op) { 1291 *expr += 2; 1292 return true; 1293 } 1294 return false; 1295 } 1296 1297 1298 template<typename QueryPolicy> 1299 status_t 1300 Expression<QueryPolicy>::InitCheck() 1301 { 1302 if (fTerm == NULL) 1303 return B_BAD_VALUE; 1304 1305 return B_OK; 1306 } 1307 1308 1309 // #pragma mark - 1310 1311 1312 template<typename QueryPolicy> 1313 Query<QueryPolicy>::Query(Context* context, Expression<QueryPolicy>* expression, 1314 uint32 flags, port_id port, uint32 token) 1315 : 1316 fContext(context), 1317 fExpression(expression), 1318 fCurrent(NULL), 1319 fIterator(NULL), 1320 fIndex(context), 1321 fFlags(flags), 1322 fPort(port), 1323 fToken(token), 1324 fNeedsEntry(false) 1325 { 1326 // If the expression has a valid root pointer, the whole tree has 1327 // already passed the sanity check, so that we don't have to check 1328 // every pointer 1329 if (context == NULL || expression == NULL || expression->Root() == NULL) 1330 return; 1331 1332 // create index on the stack and delete it afterwards 1333 fExpression->Root()->CalculateScore(fIndex); 1334 QueryPolicy::IndexUnset(fIndex); 1335 1336 fNeedsEntry = fExpression->Root()->NeedsEntry(); 1337 1338 Rewind(); 1339 } 1340 1341 1342 template<typename QueryPolicy> 1343 Query<QueryPolicy>::~Query() 1344 { 1345 delete fExpression; 1346 } 1347 1348 1349 template<typename QueryPolicy> 1350 /*static*/ status_t 1351 Query<QueryPolicy>::Create(Context* context, const char* queryString, 1352 uint32 flags, port_id port, uint32 token, Query<QueryPolicy>*& _query) 1353 { 1354 Expression<QueryPolicy>* expression 1355 = new(std::nothrow) Expression<QueryPolicy>((char*)queryString); 1356 if (expression == NULL) 1357 QUERY_RETURN_ERROR(B_NO_MEMORY); 1358 1359 if (expression->InitCheck() != B_OK) { 1360 QUERY_INFORM("Could not parse query \"%s\", stopped at: \"%s\"\n", 1361 queryString, expression->Position()); 1362 1363 delete expression; 1364 QUERY_RETURN_ERROR(B_BAD_VALUE); 1365 } 1366 1367 Query<QueryPolicy>* query = new(std::nothrow) Query<QueryPolicy>(context, 1368 expression, flags, port, token); 1369 if (query == NULL) { 1370 delete expression; 1371 QUERY_RETURN_ERROR(B_NO_MEMORY); 1372 } 1373 1374 _query = query; 1375 return B_OK; 1376 } 1377 1378 1379 template<typename QueryPolicy> 1380 status_t 1381 Query<QueryPolicy>::Rewind() 1382 { 1383 // free previous stuff 1384 1385 fStack.MakeEmpty(); 1386 1387 QueryPolicy::IndexIteratorDelete(fIterator); 1388 fIterator = NULL; 1389 fCurrent = NULL; 1390 1391 // put the whole expression on the stack 1392 1393 Stack<Term<QueryPolicy>*> stack; 1394 stack.Push(fExpression->Root()); 1395 1396 Term<QueryPolicy>* term; 1397 while (stack.Pop(&term)) { 1398 if (term->Op() < OP_EQUATION) { 1399 Operator<QueryPolicy>* op = (Operator<QueryPolicy>*)term; 1400 1401 if (op->Op() == OP_OR) { 1402 stack.Push(op->Left()); 1403 stack.Push(op->Right()); 1404 } else { 1405 // For OP_AND, we can use the scoring system to decide which 1406 // path to add 1407 if (op->Right()->Score() > op->Left()->Score()) 1408 stack.Push(op->Right()); 1409 else 1410 stack.Push(op->Left()); 1411 } 1412 } else if (term->Op() == OP_EQUATION 1413 || fStack.Push((Equation<QueryPolicy>*)term) != B_OK) 1414 QUERY_FATAL("Unknown term on stack or stack error\n"); 1415 } 1416 1417 return B_OK; 1418 } 1419 1420 1421 template<typename QueryPolicy> 1422 status_t 1423 Query<QueryPolicy>::GetNextEntry(struct dirent* dirent, size_t size) 1424 { 1425 if (fIterator != NULL) 1426 QueryPolicy::IndexIteratorResume(fIterator); 1427 1428 status_t error = _GetNextEntry(dirent, size); 1429 1430 if (fIterator != NULL) 1431 QueryPolicy::IndexIteratorSuspend(fIterator); 1432 1433 return error; 1434 } 1435 1436 1437 template<typename QueryPolicy> 1438 void 1439 Query<QueryPolicy>::LiveUpdate(Entry* entry, Node* node, const char* attribute, 1440 int32 type, const uint8* oldKey, size_t oldLength, const uint8* newKey, 1441 size_t newLength) 1442 { 1443 if (fPort < 0 || fExpression == NULL || attribute == NULL) 1444 return; 1445 1446 // TODO: check if the attribute is part of the query at all... 1447 1448 // If no entry has been supplied, but the we need one for the evaluation 1449 // (i.e. the "name" attribute is used), we invoke ourselves for all entries 1450 // referring to the given node. 1451 if (entry == NULL && fNeedsEntry) { 1452 entry = QueryPolicy::NodeGetFirstReferrer(node); 1453 while (entry) { 1454 LiveUpdate(entry, node, attribute, type, oldKey, oldLength, newKey, 1455 newLength); 1456 entry = QueryPolicy::NodeGetNextReferrer(node, entry); 1457 } 1458 return; 1459 } 1460 1461 status_t oldStatus = fExpression->Root()->Match(entry, node, attribute, 1462 type, oldKey, oldLength); 1463 status_t newStatus = fExpression->Root()->Match(entry, node, attribute, 1464 type, newKey, newLength); 1465 1466 bool entryCreated = false; 1467 bool stillInQuery = false; 1468 1469 if (oldStatus != MATCH_OK) { 1470 if (newStatus != MATCH_OK) { 1471 // nothing has changed 1472 return; 1473 } 1474 entryCreated = true; 1475 } else if (newStatus != MATCH_OK) { 1476 // entry got removed 1477 entryCreated = false; 1478 } else if ((fFlags & B_ATTR_CHANGE_NOTIFICATION) != 0) { 1479 // The entry stays in the query 1480 stillInQuery = true; 1481 } else 1482 return; 1483 1484 // notify query listeners 1485 status_t (*notify)(port_id, int32, dev_t, ino_t, const char*, ino_t); 1486 1487 if (stillInQuery) 1488 notify = notify_query_attr_changed; 1489 else if (entryCreated) 1490 notify = notify_query_entry_created; 1491 else 1492 notify = notify_query_entry_removed; 1493 1494 if (entry != NULL) { 1495 _SendEntryNotification(entry, notify); 1496 } else { 1497 entry = QueryPolicy::NodeGetFirstReferrer(node); 1498 while (entry) { 1499 _SendEntryNotification(entry, notify); 1500 entry = QueryPolicy::NodeGetNextReferrer(node, entry); 1501 } 1502 } 1503 } 1504 1505 1506 template<typename QueryPolicy> 1507 void 1508 Query<QueryPolicy>::LiveUpdateRenameMove(Entry* entry, Node* node, 1509 ino_t oldDirectoryID, const char* oldName, size_t oldLength, 1510 ino_t newDirectoryID, const char* newName, size_t newLength) 1511 { 1512 if (fPort < 0 || fExpression == NULL) 1513 return; 1514 1515 // TODO: check if the attribute is part of the query at all... 1516 1517 status_t oldStatus = fExpression->Root()->Match(entry, node, "name", 1518 B_STRING_TYPE, (const uint8*)oldName, oldLength); 1519 status_t newStatus = fExpression->Root()->Match(entry, node, "name", 1520 B_STRING_TYPE, (const uint8*)newName, newLength); 1521 1522 if (oldStatus != MATCH_OK || oldStatus != newStatus) 1523 return; 1524 1525 // The entry stays in the query, notify query listeners about the rename 1526 // or move 1527 1528 // We send a notification for the given entry, if any, or otherwise for 1529 // all entries referring to the node; 1530 if (entry != NULL) { 1531 _SendEntryNotification(entry, notify_query_entry_removed); 1532 _SendEntryNotification(entry, notify_query_entry_created); 1533 } else { 1534 entry = QueryPolicy::NodeGetFirstReferrer(node); 1535 while (entry) { 1536 _SendEntryNotification(entry, notify_query_entry_removed); 1537 _SendEntryNotification(entry, notify_query_entry_created); 1538 entry = QueryPolicy::NodeGetNextReferrer(node, entry); 1539 } 1540 } 1541 } 1542 1543 1544 template<typename QueryPolicy> 1545 status_t 1546 Query<QueryPolicy>::_GetNextEntry(struct dirent* dirent, size_t size) 1547 { 1548 // If we don't have an equation to use yet/anymore, get a new one 1549 // from the stack 1550 while (true) { 1551 if (fIterator == NULL) { 1552 if (!fStack.Pop(&fCurrent) 1553 || fCurrent == NULL) 1554 return B_ENTRY_NOT_FOUND; 1555 1556 status_t status = fCurrent->PrepareQuery(fContext, fIndex, 1557 &fIterator, fFlags & B_QUERY_NON_INDEXED); 1558 if (status == B_ENTRY_NOT_FOUND) { 1559 // try next equation 1560 continue; 1561 } 1562 1563 if (status != B_OK) 1564 return status; 1565 } 1566 if (fCurrent == NULL) 1567 QUERY_RETURN_ERROR(B_ERROR); 1568 1569 status_t status = fCurrent->GetNextMatching(fContext, fIterator, dirent, 1570 size); 1571 if (status != B_OK) { 1572 QueryPolicy::IndexIteratorDelete(fIterator); 1573 fIterator = NULL; 1574 fCurrent = NULL; 1575 } else { 1576 // only return if we have another entry 1577 return B_OK; 1578 } 1579 } 1580 } 1581 1582 1583 template<typename QueryPolicy> 1584 void 1585 Query<QueryPolicy>::_SendEntryNotification(Entry* entry, 1586 status_t (*notify)(port_id, int32, dev_t, ino_t, const char*, ino_t)) 1587 { 1588 char nameBuffer[QueryPolicy::kMaxFileNameLength]; 1589 const char* name = QueryPolicy::EntryGetNameNoCopy(entry, nameBuffer, 1590 sizeof(nameBuffer)); 1591 if (name != NULL) { 1592 notify(fPort, fToken, QueryPolicy::ContextGetVolumeID(fContext), 1593 QueryPolicy::EntryGetParentID(entry), name, 1594 QueryPolicy::EntryGetNodeID(entry)); 1595 } 1596 } 1597 1598 1599 } // namespace QueryParser 1600 1601 1602 #endif // _FILE_SYSTEMS_QUERY_PARSER_H 1603