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