PageRenderTime 54ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 1ms

/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/Query.cpp

https://bitbucket.org/ddevine/haiku
C++ | 1760 lines | 1236 code | 322 blank | 202 comment | 421 complexity | 98b0ba6bcd4bcef5d8c9c1a98ca6002e MD5 | raw file
Possible License(s): Apache-2.0, LGPL-2.0, LGPL-2.1, MPL-2.0-no-copyleft-exception, MIT, ISC, BSD-3-Clause, AGPL-1.0, GPL-2.0, GPL-3.0, LGPL-3.0
  1. /* Query - query parsing and evaluation
  2. *
  3. * The pattern matching is roughly based on code originally written
  4. * by J. Kercheval, and on code written by Kenneth Almquist, though
  5. * it shares no code.
  6. *
  7. * Copyright 2001-2006, Axel Dörfler, axeld@pinc-software.de.
  8. * This file may be used under the terms of the MIT License.
  9. */
  10. // Adjusted by Ingo Weinhold <bonefish@cs.tu-berlin.de> for usage in RAM FS.
  11. #include "Query.h"
  12. #include "Debug.h"
  13. #include "Directory.h"
  14. #include "Entry.h"
  15. #include "Misc.h"
  16. #include "Node.h"
  17. #include "Volume.h"
  18. #include "Index.h"
  19. #include <SupportDefs.h>
  20. #include <TypeConstants.h>
  21. #include <AppDefs.h>
  22. #include <fs_query.h>
  23. #include <malloc.h>
  24. #include <stdio.h>
  25. #include <string.h>
  26. // IndexWrapper
  27. // constructor
  28. IndexWrapper::IndexWrapper(Volume *volume)
  29. : fVolume(volume),
  30. fIndex(NULL)
  31. {
  32. }
  33. // SetTo
  34. status_t
  35. IndexWrapper::SetTo(const char *name)
  36. {
  37. fIndex = NULL;
  38. if (fVolume)
  39. fIndex = fVolume->FindIndex(name);
  40. return (fIndex ? B_OK : B_ENTRY_NOT_FOUND);
  41. }
  42. // Unset
  43. void
  44. IndexWrapper::Unset()
  45. {
  46. fIndex = NULL;
  47. }
  48. // Type
  49. uint32
  50. IndexWrapper::Type() const
  51. {
  52. return (fIndex ? fIndex->GetType() : 0);
  53. }
  54. // GetSize
  55. off_t
  56. IndexWrapper::GetSize() const
  57. {
  58. // Compute a fake "index size" based on the number of entries
  59. // (1024 + 16 * entry count), so we don't need to adjust the code using it.
  60. return 1024LL + (fIndex ? fIndex->CountEntries() : 0) * 16LL;
  61. }
  62. // KeySize
  63. int32
  64. IndexWrapper::KeySize() const
  65. {
  66. return (fIndex ? fIndex->GetKeyLength() : 0);
  67. }
  68. // IndexIterator
  69. // constructor
  70. IndexIterator::IndexIterator(IndexWrapper *indexWrapper)
  71. : fIndexWrapper(indexWrapper),
  72. fIterator(),
  73. fInitialized(false)
  74. {
  75. }
  76. // Find
  77. status_t
  78. IndexIterator::Find(const uint8 *const key, size_t keyLength)
  79. {
  80. status_t error = B_ENTRY_NOT_FOUND;
  81. if (fIndexWrapper && fIndexWrapper->fIndex) {
  82. // TODO: We actually don't want an exact Find() here, but rather a
  83. // FindClose().
  84. fInitialized = fIndexWrapper->fIndex->Find(key, keyLength, &fIterator);
  85. if (fInitialized)
  86. error = B_OK;
  87. }
  88. return error;
  89. }
  90. // GetNextEntry
  91. status_t
  92. IndexIterator::GetNextEntry(uint8 *buffer, uint16 *_keyLength,
  93. size_t /*bufferSize*/, Entry **_entry)
  94. {
  95. status_t error = B_ENTRY_NOT_FOUND;
  96. if (fIndexWrapper && fIndexWrapper->fIndex) {
  97. // init iterator, if not done yet
  98. if (!fInitialized) {
  99. fIndexWrapper->fIndex->GetIterator(&fIterator);
  100. fInitialized = true;
  101. }
  102. // get key
  103. size_t keyLength;
  104. if (Entry *entry = fIterator.GetCurrent(buffer, &keyLength)) {
  105. *_keyLength = keyLength;
  106. *_entry = entry;
  107. error = B_OK;
  108. }
  109. // get next entry
  110. fIterator.GetNext();
  111. }
  112. return error;
  113. }
  114. // compare_integral
  115. template<typename Key>
  116. static inline
  117. int
  118. compare_integral(const Key &a, const Key &b)
  119. {
  120. if (a < b)
  121. return -1;
  122. else if (a > b)
  123. return 1;
  124. return 0;
  125. }
  126. // compare_keys
  127. static
  128. int
  129. compare_keys(const uint8 *key1, size_t length1, const uint8 *key2,
  130. size_t length2, uint32 type)
  131. {
  132. switch (type) {
  133. case B_INT32_TYPE:
  134. return compare_integral(*(int32*)key1, *(int32*)key2);
  135. case B_UINT32_TYPE:
  136. return compare_integral(*(uint32*)key1, *(uint32*)key2);
  137. case B_INT64_TYPE:
  138. return compare_integral(*(int64*)key1, *(int64*)key2);
  139. case B_UINT64_TYPE:
  140. return compare_integral(*(uint64*)key1, *(uint64*)key2);
  141. case B_FLOAT_TYPE:
  142. return compare_integral(*(float*)key1, *(float*)key2);
  143. case B_DOUBLE_TYPE:
  144. return compare_integral(*(double*)key1, *(double*)key2);
  145. case B_STRING_TYPE:
  146. {
  147. int result = strncmp((const char*)key1, (const char*)key2,
  148. min(length1, length2));
  149. if (result == 0) {
  150. result = compare_integral(strnlen((const char*)key1, length1),
  151. strnlen((const char*)key2, length2));
  152. }
  153. return result;
  154. }
  155. }
  156. return -1;
  157. }
  158. // compareKeys
  159. static inline
  160. int
  161. compareKeys(uint32 type, const uint8 *key1, size_t length1, const uint8 *key2,
  162. size_t length2)
  163. {
  164. return compare_keys(key1, length1, key2, length2, type);
  165. }
  166. // The parser has a very static design, but it will do what is required.
  167. //
  168. // ParseOr(), ParseAnd(), ParseEquation() are guarantying the operator
  169. // precedence, that is =,!=,>,<,>=,<= .. && .. ||.
  170. // Apparently, the "!" (not) can only be used with brackets.
  171. //
  172. // If you think that there are too few NULL pointer checks in some places
  173. // of the code, just read the beginning of the query constructor.
  174. // The API is not fully available, just the Query and the Expression class
  175. // are.
  176. enum ops {
  177. OP_NONE,
  178. OP_AND,
  179. OP_OR,
  180. OP_EQUATION,
  181. OP_EQUAL,
  182. OP_UNEQUAL,
  183. OP_GREATER_THAN,
  184. OP_LESS_THAN,
  185. OP_GREATER_THAN_OR_EQUAL,
  186. OP_LESS_THAN_OR_EQUAL,
  187. };
  188. enum match {
  189. NO_MATCH = 0,
  190. MATCH_OK = 1,
  191. MATCH_BAD_PATTERN = -2,
  192. MATCH_INVALID_CHARACTER
  193. };
  194. // return values from isValidPattern()
  195. enum {
  196. PATTERN_INVALID_ESCAPE = -3,
  197. PATTERN_INVALID_RANGE,
  198. PATTERN_INVALID_SET
  199. };
  200. union value {
  201. int64 Int64;
  202. uint64 Uint64;
  203. int32 Int32;
  204. uint32 Uint32;
  205. float Float;
  206. double Double;
  207. char CString[kMaxIndexKeyLength];
  208. };
  209. // B_MIME_STRING_TYPE is defined in storage/Mime.h, but we
  210. // don't need the whole file here; the type can't change anyway
  211. #ifndef _MIME_H
  212. # define B_MIME_STRING_TYPE 'MIMS'
  213. #endif
  214. class Term {
  215. public:
  216. Term(int8 op) : fOp(op), fParent(NULL) {}
  217. virtual ~Term() {}
  218. int8 Op() const { return fOp; }
  219. void SetParent(Term *parent) { fParent = parent; }
  220. Term *Parent() const { return fParent; }
  221. virtual status_t Match(Entry *entry, Node* node,
  222. const char *attribute = NULL, int32 type = 0,
  223. const uint8 *key = NULL, size_t size = 0) = 0;
  224. virtual void Complement() = 0;
  225. virtual void CalculateScore(IndexWrapper &index) = 0;
  226. virtual int32 Score() const = 0;
  227. virtual status_t InitCheck() = 0;
  228. virtual bool NeedsEntry() = 0;
  229. #ifdef DEBUG
  230. virtual void PrintToStream() = 0;
  231. #endif
  232. protected:
  233. int8 fOp;
  234. Term *fParent;
  235. };
  236. // Although an Equation object is quite independent from the volume on which
  237. // the query is run, there are some dependencies that are produced while
  238. // querying:
  239. // The type/size of the value, the score, and if it has an index or not.
  240. // So you could run more than one query on the same volume, but it might return
  241. // wrong values when it runs concurrently on another volume.
  242. // That's not an issue right now, because we run single-threaded and don't use
  243. // queries more than once.
  244. class Equation : public Term {
  245. public:
  246. Equation(char **expr);
  247. virtual ~Equation();
  248. virtual status_t InitCheck();
  249. status_t ParseQuotedString(char **_start, char **_end);
  250. char *CopyString(char *start, char *end);
  251. virtual status_t Match(Entry *entry, Node* node,
  252. const char *attribute = NULL, int32 type = 0,
  253. const uint8 *key = NULL, size_t size = 0);
  254. virtual void Complement();
  255. status_t PrepareQuery(Volume *volume, IndexWrapper &index, IndexIterator **iterator,
  256. bool queryNonIndexed);
  257. status_t GetNextMatching(Volume *volume, IndexIterator *iterator,
  258. struct dirent *dirent, size_t bufferSize);
  259. virtual void CalculateScore(IndexWrapper &index);
  260. virtual int32 Score() const { return fScore; }
  261. virtual bool NeedsEntry();
  262. #ifdef DEBUG
  263. virtual void PrintToStream();
  264. #endif
  265. private:
  266. Equation(const Equation &);
  267. Equation &operator=(const Equation &);
  268. // no implementation
  269. status_t ConvertValue(type_code type);
  270. bool CompareTo(const uint8 *value, uint16 size);
  271. uint8 *Value() const { return (uint8 *)&fValue; }
  272. status_t MatchEmptyString();
  273. char *fAttribute;
  274. char *fString;
  275. union value fValue;
  276. type_code fType;
  277. size_t fSize;
  278. bool fIsPattern;
  279. int32 fScore;
  280. bool fHasIndex;
  281. };
  282. class Operator : public Term {
  283. public:
  284. Operator(Term *,int8,Term *);
  285. virtual ~Operator();
  286. Term *Left() const { return fLeft; }
  287. Term *Right() const { return fRight; }
  288. virtual status_t Match(Entry *entry, Node* node,
  289. const char *attribute = NULL, int32 type = 0,
  290. const uint8 *key = NULL, size_t size = 0);
  291. virtual void Complement();
  292. virtual void CalculateScore(IndexWrapper &index);
  293. virtual int32 Score() const;
  294. virtual status_t InitCheck();
  295. virtual bool NeedsEntry();
  296. //Term *Copy() const;
  297. #ifdef DEBUG
  298. virtual void PrintToStream();
  299. #endif
  300. private:
  301. Operator(const Operator &);
  302. Operator &operator=(const Operator &);
  303. // no implementation
  304. Term *fLeft,*fRight;
  305. };
  306. //---------------------------------
  307. void
  308. skipWhitespace(char **expr, int32 skip = 0)
  309. {
  310. char *string = (*expr) + skip;
  311. while (*string == ' ' || *string == '\t') string++;
  312. *expr = string;
  313. }
  314. void
  315. skipWhitespaceReverse(char **expr,char *stop)
  316. {
  317. char *string = *expr;
  318. while (string > stop && (*string == ' ' || *string == '\t')) string--;
  319. *expr = string;
  320. }
  321. // #pragma mark -
  322. uint32
  323. utf8ToUnicode(char **string)
  324. {
  325. uint8 *bytes = (uint8 *)*string;
  326. int32 length;
  327. uint8 mask = 0x1f;
  328. switch (bytes[0] & 0xf0) {
  329. case 0xc0:
  330. case 0xd0: length = 2; break;
  331. case 0xe0: length = 3; break;
  332. case 0xf0:
  333. mask = 0x0f;
  334. length = 4;
  335. break;
  336. default:
  337. // valid 1-byte character
  338. // and invalid characters
  339. (*string)++;
  340. return bytes[0];
  341. }
  342. uint32 c = bytes[0] & mask;
  343. int32 i = 1;
  344. for (;i < length && (bytes[i] & 0x80) > 0;i++)
  345. c = (c << 6) | (bytes[i] & 0x3f);
  346. if (i < length) {
  347. // invalid character
  348. (*string)++;
  349. return (uint32)bytes[0];
  350. }
  351. *string += length;
  352. return c;
  353. }
  354. int32
  355. getFirstPatternSymbol(char *string)
  356. {
  357. char c;
  358. for (int32 index = 0;(c = *string++);index++) {
  359. if (c == '*' || c == '?' || c == '[')
  360. return index;
  361. }
  362. return -1;
  363. }
  364. bool
  365. isPattern(char *string)
  366. {
  367. return getFirstPatternSymbol(string) >= 0 ? true : false;
  368. }
  369. status_t
  370. isValidPattern(char *pattern)
  371. {
  372. while (*pattern) {
  373. switch (*pattern++) {
  374. case '\\':
  375. // the escape character must not be at the end of the pattern
  376. if (!*pattern++)
  377. return PATTERN_INVALID_ESCAPE;
  378. break;
  379. case '[':
  380. if (pattern[0] == ']' || !pattern[0])
  381. return PATTERN_INVALID_SET;
  382. while (*pattern != ']') {
  383. if (*pattern == '\\' && !*++pattern)
  384. return PATTERN_INVALID_ESCAPE;
  385. if (!*pattern)
  386. return PATTERN_INVALID_SET;
  387. if (pattern[0] == '-' && pattern[1] == '-')
  388. return PATTERN_INVALID_RANGE;
  389. pattern++;
  390. }
  391. break;
  392. }
  393. }
  394. return B_OK;
  395. }
  396. /** Matches the string against the given wildcard pattern.
  397. * Returns either MATCH_OK, or NO_MATCH when everything went fine,
  398. * or values < 0 (see enum at the top of Query.cpp) if an error
  399. * occurs
  400. */
  401. status_t
  402. matchString(char *pattern, char *string)
  403. {
  404. while (*pattern) {
  405. // end of string == valid end of pattern?
  406. if (!string[0]) {
  407. while (pattern[0] == '*')
  408. pattern++;
  409. return !pattern[0] ? MATCH_OK : NO_MATCH;
  410. }
  411. switch (*pattern++) {
  412. case '?':
  413. {
  414. // match exactly one UTF-8 character; we are
  415. // not interested in the result
  416. utf8ToUnicode(&string);
  417. break;
  418. }
  419. case '*':
  420. {
  421. // compact pattern
  422. while (true) {
  423. if (pattern[0] == '?') {
  424. if (!*++string)
  425. return NO_MATCH;
  426. } else if (pattern[0] != '*')
  427. break;
  428. pattern++;
  429. }
  430. // if the pattern is done, we have matched the string
  431. if (!pattern[0])
  432. return MATCH_OK;
  433. while(true) {
  434. // we have removed all occurences of '*' and '?'
  435. if (pattern[0] == string[0]
  436. || pattern[0] == '['
  437. || pattern[0] == '\\') {
  438. status_t status = matchString(pattern,string);
  439. if (status < B_OK || status == MATCH_OK)
  440. return status;
  441. }
  442. // we could be nice here and just jump to the next
  443. // UTF-8 character - but we wouldn't gain that much
  444. // and it'd be slower (since we're checking for
  445. // equality before entering the recursion)
  446. if (!*++string)
  447. return NO_MATCH;
  448. }
  449. break;
  450. }
  451. case '[':
  452. {
  453. bool invert = false;
  454. if (pattern[0] == '^' || pattern[0] == '!') {
  455. invert = true;
  456. pattern++;
  457. }
  458. if (!pattern[0] || pattern[0] == ']')
  459. return MATCH_BAD_PATTERN;
  460. uint32 c = utf8ToUnicode(&string);
  461. bool matched = false;
  462. while (pattern[0] != ']') {
  463. if (!pattern[0])
  464. return MATCH_BAD_PATTERN;
  465. if (pattern[0] == '\\')
  466. pattern++;
  467. uint32 first = utf8ToUnicode(&pattern);
  468. // Does this character match, or is this a range?
  469. if (first == c) {
  470. matched = true;
  471. break;
  472. } else if (pattern[0] == '-' && pattern[1] != ']' && pattern[1]) {
  473. pattern++;
  474. if (pattern[0] == '\\') {
  475. pattern++;
  476. if (!pattern[0])
  477. return MATCH_BAD_PATTERN;
  478. }
  479. uint32 last = utf8ToUnicode(&pattern);
  480. if (c >= first && c <= last) {
  481. matched = true;
  482. break;
  483. }
  484. }
  485. }
  486. if (invert)
  487. matched = !matched;
  488. if (matched) {
  489. while (pattern[0] != ']') {
  490. if (!pattern[0])
  491. return MATCH_BAD_PATTERN;
  492. pattern++;
  493. }
  494. pattern++;
  495. break;
  496. }
  497. return NO_MATCH;
  498. }
  499. case '\\':
  500. if (!pattern[0])
  501. return MATCH_BAD_PATTERN;
  502. // supposed to fall through
  503. default:
  504. if (pattern[-1] != string[0])
  505. return NO_MATCH;
  506. string++;
  507. break;
  508. }
  509. }
  510. if (string[0])
  511. return NO_MATCH;
  512. return MATCH_OK;
  513. }
  514. // #pragma mark -
  515. Equation::Equation(char **expr)
  516. : Term(OP_EQUATION),
  517. fAttribute(NULL),
  518. fString(NULL),
  519. fType(0),
  520. fIsPattern(false)
  521. {
  522. char *string = *expr;
  523. char *start = string;
  524. char *end = NULL;
  525. // Since the equation is the integral part of any query, we're just parsing
  526. // the whole thing here.
  527. // The whitespace at the start is already removed in Expression::ParseEquation()
  528. if (*start == '"' || *start == '\'') {
  529. // string is quoted (start has to be on the beginning of a string)
  530. if (ParseQuotedString(&start, &end) < B_OK)
  531. return;
  532. // set string to a valid start of the equation symbol
  533. string = end + 2;
  534. skipWhitespace(&string);
  535. if (*string != '=' && *string != '<' && *string != '>' && *string != '!') {
  536. *expr = string;
  537. return;
  538. }
  539. } else {
  540. // search the (in)equation for the actual equation symbol (and for other operators
  541. // in case the equation is malformed)
  542. while (*string && *string != '=' && *string != '<' && *string != '>' && *string != '!'
  543. && *string != '&' && *string != '|')
  544. string++;
  545. // get the attribute string (and trim whitespace), in case
  546. // the string was not quoted
  547. end = string - 1;
  548. skipWhitespaceReverse(&end, start);
  549. }
  550. // attribute string is empty (which is not allowed)
  551. if (start > end)
  552. return;
  553. // at this point, "start" points to the beginning of the string, "end" points
  554. // to the last character of the string, and "string" points to the first
  555. // character of the equation symbol
  556. // test for the right symbol (as this doesn't need any memory)
  557. switch (*string) {
  558. case '=':
  559. fOp = OP_EQUAL;
  560. break;
  561. case '>':
  562. fOp = *(string + 1) == '=' ? OP_GREATER_THAN_OR_EQUAL : OP_GREATER_THAN;
  563. break;
  564. case '<':
  565. fOp = *(string + 1) == '=' ? OP_LESS_THAN_OR_EQUAL : OP_LESS_THAN;
  566. break;
  567. case '!':
  568. if (*(string + 1) != '=')
  569. return;
  570. fOp = OP_UNEQUAL;
  571. break;
  572. // any invalid characters will be rejected
  573. default:
  574. *expr = string;
  575. return;
  576. }
  577. // lets change "start" to point to the first character after the symbol
  578. if (*(string + 1) == '=')
  579. string++;
  580. string++;
  581. skipWhitespace(&string);
  582. // allocate & copy the attribute string
  583. fAttribute = CopyString(start, end);
  584. if (fAttribute == NULL)
  585. return;
  586. start = string;
  587. if (*start == '"' || *start == '\'') {
  588. // string is quoted (start has to be on the beginning of a string)
  589. if (ParseQuotedString(&start, &end) < B_OK)
  590. return;
  591. string = end + 2;
  592. skipWhitespace(&string);
  593. } else {
  594. while (*string && *string != '&' && *string != '|' && *string != ')')
  595. string++;
  596. end = string - 1;
  597. skipWhitespaceReverse(&end, start);
  598. }
  599. // at this point, "start" will point to the first character of the value,
  600. // "end" will point to its last character, and "start" to the first non-
  601. // whitespace character after the value string
  602. fString = CopyString(start, end);
  603. if (fString == NULL)
  604. return;
  605. // patterns are only allowed for these operations (and strings)
  606. if (fOp == OP_EQUAL || fOp == OP_UNEQUAL) {
  607. fIsPattern = isPattern(fString);
  608. if (fIsPattern && isValidPattern(fString) < B_OK) {
  609. // we only want to have valid patterns; setting fString
  610. // to NULL will cause InitCheck() to fail
  611. free(fString);
  612. fString = NULL;
  613. }
  614. }
  615. *expr = string;
  616. }
  617. Equation::~Equation()
  618. {
  619. if (fAttribute != NULL)
  620. free(fAttribute);
  621. if (fString != NULL)
  622. free(fString);
  623. }
  624. status_t
  625. Equation::InitCheck()
  626. {
  627. if (fAttribute == NULL
  628. || fString == NULL
  629. || fOp == OP_NONE)
  630. return B_BAD_VALUE;
  631. return B_OK;
  632. }
  633. status_t
  634. Equation::ParseQuotedString(char **_start, char **_end)
  635. {
  636. char *start = *_start;
  637. char quote = *start++;
  638. char *end = start;
  639. for (;*end && *end != quote;end++) {
  640. if (*end == '\\')
  641. end++;
  642. }
  643. if (*end == '\0')
  644. return B_BAD_VALUE;
  645. *_start = start;
  646. *_end = end - 1;
  647. return B_OK;
  648. }
  649. char *
  650. Equation::CopyString(char *start, char *end)
  651. {
  652. // end points to the last character of the string - and the length
  653. // also has to include the null-termination
  654. int32 length = end + 2 - start;
  655. // just to make sure; since that's the max. attribute name length and
  656. // the max. string in an index, it make sense to have it that way
  657. if (length > (int32)kMaxIndexKeyLength || length <= 0)
  658. return NULL;
  659. char *copy = (char *)malloc(length);
  660. if (copy == NULL)
  661. return NULL;
  662. memcpy(copy,start,length - 1);
  663. copy[length - 1] = '\0';
  664. return copy;
  665. }
  666. status_t
  667. Equation::ConvertValue(type_code type)
  668. {
  669. // Has the type already been converted?
  670. if (type == fType)
  671. return B_OK;
  672. char *string = fString;
  673. switch (type) {
  674. case B_MIME_STRING_TYPE:
  675. type = B_STRING_TYPE;
  676. // supposed to fall through
  677. case B_STRING_TYPE:
  678. strncpy(fValue.CString, string, kMaxIndexKeyLength);
  679. fValue.CString[kMaxIndexKeyLength - 1] = '\0';
  680. fSize = strlen(fValue.CString);
  681. break;
  682. case B_INT32_TYPE:
  683. fValue.Int32 = strtol(string, &string, 0);
  684. fSize = sizeof(int32);
  685. break;
  686. case B_UINT32_TYPE:
  687. fValue.Int32 = strtoul(string, &string, 0);
  688. fSize = sizeof(uint32);
  689. break;
  690. case B_INT64_TYPE:
  691. fValue.Int64 = strtoll(string, &string, 0);
  692. fSize = sizeof(int64);
  693. break;
  694. case B_UINT64_TYPE:
  695. fValue.Uint64 = strtoull(string, &string, 0);
  696. fSize = sizeof(uint64);
  697. break;
  698. case B_FLOAT_TYPE:
  699. fValue.Float = strtod(string, &string);
  700. fSize = sizeof(float);
  701. break;
  702. case B_DOUBLE_TYPE:
  703. fValue.Double = strtod(string, &string);
  704. fSize = sizeof(double);
  705. break;
  706. default:
  707. FATAL(("query value conversion to 0x%lx requested!\n", type));
  708. // should we fail here or just do a safety int32 conversion?
  709. return B_ERROR;
  710. }
  711. fType = type;
  712. // patterns are only allowed for string types
  713. if (fType != B_STRING_TYPE && fIsPattern)
  714. fIsPattern = false;
  715. return B_OK;
  716. }
  717. /** Returns true when the key matches the equation. You have to
  718. * call ConvertValue() before this one.
  719. */
  720. bool
  721. Equation::CompareTo(const uint8 *value, uint16 size)
  722. {
  723. int32 compare;
  724. // fIsPattern is only true if it's a string type, and fOp OP_EQUAL, or OP_UNEQUAL
  725. if (fIsPattern) {
  726. // we have already validated the pattern, so we don't check for failing
  727. // here - if something is broken, and matchString() returns an error,
  728. // we just don't match
  729. compare = matchString(fValue.CString, (char *)value) == MATCH_OK ? 0 : 1;
  730. } else
  731. compare = compareKeys(fType, value, size, Value(), fSize);
  732. switch (fOp) {
  733. case OP_EQUAL:
  734. return compare == 0;
  735. case OP_UNEQUAL:
  736. return compare != 0;
  737. case OP_LESS_THAN:
  738. return compare < 0;
  739. case OP_LESS_THAN_OR_EQUAL:
  740. return compare <= 0;
  741. case OP_GREATER_THAN:
  742. return compare > 0;
  743. case OP_GREATER_THAN_OR_EQUAL:
  744. return compare >= 0;
  745. }
  746. FATAL(("Unknown/Unsupported operation: %d\n", fOp));
  747. return false;
  748. }
  749. void
  750. Equation::Complement()
  751. {
  752. D(if (fOp <= OP_EQUATION || fOp > OP_LESS_THAN_OR_EQUAL) {
  753. FATAL(("op out of range!"));
  754. return;
  755. });
  756. int8 complementOp[] = {OP_UNEQUAL, OP_EQUAL, OP_LESS_THAN_OR_EQUAL,
  757. OP_GREATER_THAN_OR_EQUAL, OP_LESS_THAN, OP_GREATER_THAN};
  758. fOp = complementOp[fOp - OP_EQUAL];
  759. }
  760. status_t
  761. Equation::MatchEmptyString()
  762. {
  763. // there is no matching attribute, we will just bail out if we
  764. // already know that our value is not of a string type.
  765. // If not, it will be converted to a string - and then be compared with "".
  766. // That's why we have to call ConvertValue() here - but it will be
  767. // a cheap call for the next time
  768. // Should we do this only for OP_UNEQUAL?
  769. if (fType != 0 && fType != B_STRING_TYPE)
  770. return NO_MATCH;
  771. status_t status = ConvertValue(B_STRING_TYPE);
  772. if (status == B_OK)
  773. status = CompareTo((const uint8 *)"", fSize) ? MATCH_OK : NO_MATCH;
  774. return status;
  775. }
  776. /** Matches the inode's attribute value with the equation.
  777. * Returns MATCH_OK if it matches, NO_MATCH if not, < 0 if something went wrong
  778. */
  779. status_t
  780. Equation::Match(Entry *entry, Node* node, const char *attributeName, int32 type,
  781. const uint8 *key, size_t size)
  782. {
  783. // get a pointer to the attribute in question
  784. union value value;
  785. const uint8 *buffer;
  786. // first, check if we are matching for a live query and use that value
  787. if (attributeName != NULL && !strcmp(fAttribute, attributeName)) {
  788. if (key == NULL) {
  789. if (type == B_STRING_TYPE) {
  790. // special case: a NULL "name" means the entry has been removed
  791. // or not yet been added -- we refuse to match, whatever the
  792. // pattern
  793. if (!strcmp(fAttribute, "name"))
  794. return NO_MATCH;
  795. return MatchEmptyString();
  796. }
  797. return NO_MATCH;
  798. }
  799. buffer = const_cast<uint8 *>(key);
  800. } else if (!strcmp(fAttribute, "name")) {
  801. // if not, check for "fake" attributes, "name", "size", "last_modified",
  802. if (!entry)
  803. return B_ERROR;
  804. buffer = (uint8 *)entry->GetName();
  805. if (buffer == NULL)
  806. return B_ERROR;
  807. type = B_STRING_TYPE;
  808. size = strlen((const char *)buffer);
  809. } else if (!strcmp(fAttribute,"size")) {
  810. value.Int64 = node->GetSize();
  811. buffer = (uint8 *)&value;
  812. type = B_INT64_TYPE;
  813. } else if (!strcmp(fAttribute,"last_modified")) {
  814. value.Int32 = node->GetMTime();
  815. buffer = (uint8 *)&value;
  816. type = B_INT32_TYPE;
  817. } else {
  818. // then for attributes
  819. Attribute *attribute = NULL;
  820. if (node->FindAttribute(fAttribute, &attribute) == B_OK) {
  821. attribute->GetKey(&buffer, &size);
  822. type = attribute->GetType();
  823. } else
  824. return MatchEmptyString();
  825. }
  826. // prepare own value for use, if it is possible to convert it
  827. status_t status = ConvertValue(type);
  828. if (status == B_OK)
  829. status = CompareTo(buffer, size) ? MATCH_OK : NO_MATCH;
  830. RETURN_ERROR(status);
  831. }
  832. void
  833. Equation::CalculateScore(IndexWrapper &index)
  834. {
  835. // As always, these values could be tuned and refined.
  836. // And the code could also need some real world testing :-)
  837. // do we have to operate on a "foreign" index?
  838. if (fOp == OP_UNEQUAL || index.SetTo(fAttribute) < B_OK) {
  839. fScore = 0;
  840. return;
  841. }
  842. // if we have a pattern, how much does it help our search?
  843. if (fIsPattern)
  844. fScore = getFirstPatternSymbol(fString) << 3;
  845. else {
  846. // Score by operator
  847. if (fOp == OP_EQUAL)
  848. // higher than pattern="255 chars+*"
  849. fScore = 2048;
  850. else
  851. // the pattern search is regarded cheaper when you have at
  852. // least one character to set your index to
  853. fScore = 5;
  854. }
  855. // take index size into account (1024 is the current node size
  856. // in our B+trees)
  857. // 2048 * 2048 == 4194304 is the maximum score (for an empty
  858. // tree, since the header + 1 node are already 2048 bytes)
  859. fScore = fScore * ((2048 * 1024LL) / index.GetSize());
  860. }
  861. status_t
  862. Equation::PrepareQuery(Volume */*volume*/, IndexWrapper &index, IndexIterator **iterator, bool queryNonIndexed)
  863. {
  864. status_t status = index.SetTo(fAttribute);
  865. // if we should query attributes without an index, we can just proceed here
  866. if (status < B_OK && !queryNonIndexed)
  867. return B_ENTRY_NOT_FOUND;
  868. type_code type;
  869. // special case for OP_UNEQUAL - it will always operate through the whole index
  870. // but we need the call to the original index to get the correct type
  871. if (status < B_OK || fOp == OP_UNEQUAL) {
  872. // Try to get an index that holds all files (name)
  873. // Also sets the default type for all attributes without index
  874. // to string.
  875. type = status < B_OK ? B_STRING_TYPE : index.Type();
  876. if (index.SetTo("name") < B_OK)
  877. return B_ENTRY_NOT_FOUND;
  878. fHasIndex = false;
  879. } else {
  880. fHasIndex = true;
  881. type = index.Type();
  882. }
  883. if (ConvertValue(type) < B_OK)
  884. return B_BAD_VALUE;
  885. *iterator = new IndexIterator(&index);
  886. if (*iterator == NULL)
  887. return B_NO_MEMORY;
  888. if ((fOp == OP_EQUAL || fOp == OP_GREATER_THAN || fOp == OP_GREATER_THAN_OR_EQUAL
  889. || fIsPattern)
  890. && fHasIndex) {
  891. // set iterator to the exact position
  892. int32 keySize = index.KeySize();
  893. // at this point, fIsPattern is only true if it's a string type, and fOp
  894. // is either OP_EQUAL or OP_UNEQUAL
  895. if (fIsPattern) {
  896. // let's see if we can use the beginning of the key for positioning
  897. // the iterator and adjust the key size; if not, just leave the
  898. // iterator at the start and return success
  899. keySize = getFirstPatternSymbol(fString);
  900. if (keySize <= 0)
  901. return B_OK;
  902. }
  903. if (keySize == 0) {
  904. // B_STRING_TYPE doesn't have a fixed length, so it was set
  905. // to 0 before - we compute the correct value here
  906. if (fType == B_STRING_TYPE) {
  907. keySize = strlen(fValue.CString);
  908. // The empty string is a special case - we normally don't check
  909. // for the trailing null byte, in the case for the empty string
  910. // we do it explicitly, because there can't be keys in the B+tree
  911. // with a length of zero
  912. if (keySize == 0)
  913. keySize = 1;
  914. } else
  915. RETURN_ERROR(B_ENTRY_NOT_FOUND);
  916. }
  917. status = (*iterator)->Find(Value(), keySize);
  918. if (fOp == OP_EQUAL && !fIsPattern)
  919. return status;
  920. else if (status == B_ENTRY_NOT_FOUND
  921. && (fIsPattern || fOp == OP_GREATER_THAN || fOp == OP_GREATER_THAN_OR_EQUAL))
  922. return B_OK;
  923. RETURN_ERROR(status);
  924. }
  925. return B_OK;
  926. }
  927. status_t
  928. Equation::GetNextMatching(Volume *volume, IndexIterator *iterator,
  929. struct dirent *dirent, size_t bufferSize)
  930. {
  931. while (true) {
  932. union value indexValue;
  933. uint16 keyLength;
  934. Entry *entry = NULL;
  935. status_t status = iterator->GetNextEntry((uint8*)&indexValue, &keyLength,
  936. (uint16)sizeof(indexValue), &entry);
  937. if (status < B_OK)
  938. return status;
  939. // only compare against the index entry when this is the correct
  940. // index for the equation
  941. if (fHasIndex && !CompareTo((uint8 *)&indexValue, keyLength)) {
  942. // They aren't equal? let the operation decide what to do
  943. // Since we always start at the beginning of the index (or the correct
  944. // position), only some needs to be stopped if the entry doesn't fit.
  945. if (fOp == OP_LESS_THAN
  946. || fOp == OP_LESS_THAN_OR_EQUAL
  947. || (fOp == OP_EQUAL && !fIsPattern))
  948. return B_ENTRY_NOT_FOUND;
  949. continue;
  950. }
  951. // ToDo: check user permissions here - but which one?!
  952. // we could filter out all those where we don't have
  953. // read access... (we should check for every parent
  954. // directory if the X_OK is allowed)
  955. // Although it's quite expensive to open all parents,
  956. // it's likely that the application that runs the
  957. // query will do something similar (and we don't have
  958. // to do it for root, either).
  959. // go up in the tree until a &&-operator is found, and check if the
  960. // inode matches with the rest of the expression - we don't have to
  961. // check ||-operators for that
  962. Term *term = this;
  963. status = MATCH_OK;
  964. if (!fHasIndex)
  965. status = Match(entry, entry->GetNode());
  966. while (term != NULL && status == MATCH_OK) {
  967. Operator *parent = (Operator *)term->Parent();
  968. if (parent == NULL)
  969. break;
  970. if (parent->Op() == OP_AND) {
  971. // choose the other child of the parent
  972. Term *other = parent->Right();
  973. if (other == term)
  974. other = parent->Left();
  975. if (other == NULL) {
  976. FATAL(("&&-operator has only one child... (parent = %p)\n", parent));
  977. break;
  978. }
  979. status = other->Match(entry, entry->GetNode());
  980. if (status < 0) {
  981. REPORT_ERROR(status);
  982. status = NO_MATCH;
  983. }
  984. }
  985. term = (Term *)parent;
  986. }
  987. if (status == MATCH_OK) {
  988. size_t nameLen = strlen(entry->GetName());
  989. // check, whether the entry fits into the buffer,
  990. // and fill it in
  991. size_t length = (dirent->d_name + nameLen + 1) - (char*)dirent;
  992. if (length > bufferSize)
  993. RETURN_ERROR(B_BUFFER_OVERFLOW);
  994. dirent->d_dev = volume->GetID();
  995. dirent->d_ino = entry->GetNode()->GetID();
  996. dirent->d_pdev = volume->GetID();
  997. dirent->d_pino = entry->GetParent()->GetID();
  998. memcpy(dirent->d_name, entry->GetName(), nameLen);
  999. dirent->d_name[nameLen] = '\0';
  1000. dirent->d_reclen = length;
  1001. }
  1002. if (status == MATCH_OK)
  1003. return B_OK;
  1004. }
  1005. RETURN_ERROR(B_ERROR);
  1006. }
  1007. bool
  1008. Equation::NeedsEntry()
  1009. {
  1010. return strcmp(fAttribute, "name") == 0;
  1011. }
  1012. // #pragma mark -
  1013. Operator::Operator(Term *left, int8 op, Term *right)
  1014. : Term(op),
  1015. fLeft(left),
  1016. fRight(right)
  1017. {
  1018. if (left)
  1019. left->SetParent(this);
  1020. if (right)
  1021. right->SetParent(this);
  1022. }
  1023. Operator::~Operator()
  1024. {
  1025. delete fLeft;
  1026. delete fRight;
  1027. }
  1028. status_t
  1029. Operator::Match(Entry *entry, Node* node, const char *attribute,
  1030. int32 type, const uint8 *key, size_t size)
  1031. {
  1032. if (fOp == OP_AND) {
  1033. status_t status = fLeft->Match(entry, node, attribute, type, key, size);
  1034. if (status != MATCH_OK)
  1035. return status;
  1036. return fRight->Match(entry, node, attribute, type, key, size);
  1037. } else {
  1038. // choose the term with the better score for OP_OR
  1039. if (fRight->Score() > fLeft->Score()) {
  1040. status_t status = fRight->Match(entry, node, attribute, type, key,
  1041. size);
  1042. if (status != NO_MATCH)
  1043. return status;
  1044. }
  1045. return fLeft->Match(entry, node, attribute, type, key, size);
  1046. }
  1047. }
  1048. void
  1049. Operator::Complement()
  1050. {
  1051. if (fOp == OP_AND)
  1052. fOp = OP_OR;
  1053. else
  1054. fOp = OP_AND;
  1055. fLeft->Complement();
  1056. fRight->Complement();
  1057. }
  1058. void
  1059. Operator::CalculateScore(IndexWrapper &index)
  1060. {
  1061. fLeft->CalculateScore(index);
  1062. fRight->CalculateScore(index);
  1063. }
  1064. int32
  1065. Operator::Score() const
  1066. {
  1067. if (fOp == OP_AND) {
  1068. // return the one with the better score
  1069. if (fRight->Score() > fLeft->Score())
  1070. return fRight->Score();
  1071. return fLeft->Score();
  1072. }
  1073. // for OP_OR, be honest, and return the one with the worse score
  1074. if (fRight->Score() < fLeft->Score())
  1075. return fRight->Score();
  1076. return fLeft->Score();
  1077. }
  1078. status_t
  1079. Operator::InitCheck()
  1080. {
  1081. if (fOp != OP_AND && fOp != OP_OR
  1082. || fLeft == NULL || fLeft->InitCheck() < B_OK
  1083. || fRight == NULL || fRight->InitCheck() < B_OK)
  1084. return B_ERROR;
  1085. return B_OK;
  1086. }
  1087. bool
  1088. Operator::NeedsEntry()
  1089. {
  1090. return ((fLeft && fLeft->NeedsEntry()) || (fRight && fRight->NeedsEntry()));
  1091. }
  1092. #if 0
  1093. Term *
  1094. Operator::Copy() const
  1095. {
  1096. if (fEquation != NULL) {
  1097. Equation *equation = new Equation(*fEquation);
  1098. if (equation == NULL)
  1099. return NULL;
  1100. Term *term = new Term(equation);
  1101. if (term == NULL)
  1102. delete equation;
  1103. return term;
  1104. }
  1105. Term *left = NULL, *right = NULL;
  1106. if (fLeft != NULL && (left = fLeft->Copy()) == NULL)
  1107. return NULL;
  1108. if (fRight != NULL && (right = fRight->Copy()) == NULL) {
  1109. delete left;
  1110. return NULL;
  1111. }
  1112. Term *term = new Term(left,fOp,right);
  1113. if (term == NULL) {
  1114. delete left;
  1115. delete right;
  1116. return NULL;
  1117. }
  1118. return term;
  1119. }
  1120. #endif
  1121. // #pragma mark -
  1122. #ifdef DEBUG
  1123. void
  1124. Operator::PrintToStream()
  1125. {
  1126. D(__out("( "));
  1127. if (fLeft != NULL)
  1128. fLeft->PrintToStream();
  1129. char *op;
  1130. switch (fOp) {
  1131. case OP_OR: op = "OR"; break;
  1132. case OP_AND: op = "AND"; break;
  1133. default: op = "?"; break;
  1134. }
  1135. D(__out(" %s ",op));
  1136. if (fRight != NULL)
  1137. fRight->PrintToStream();
  1138. D(__out(" )"));
  1139. }
  1140. void
  1141. Equation::PrintToStream()
  1142. {
  1143. char *symbol = "???";
  1144. switch (fOp) {
  1145. case OP_EQUAL: symbol = "=="; break;
  1146. case OP_UNEQUAL: symbol = "!="; break;
  1147. case OP_GREATER_THAN: symbol = ">"; break;
  1148. case OP_GREATER_THAN_OR_EQUAL: symbol = ">="; break;
  1149. case OP_LESS_THAN: symbol = "<"; break;
  1150. case OP_LESS_THAN_OR_EQUAL: symbol = "<="; break;
  1151. }
  1152. D(__out("[\"%s\" %s \"%s\"]", fAttribute, symbol, fString));
  1153. }
  1154. #endif /* DEBUG */
  1155. // #pragma mark -
  1156. Expression::Expression(char *expr)
  1157. {
  1158. if (expr == NULL)
  1159. return;
  1160. fTerm = ParseOr(&expr);
  1161. if (fTerm != NULL && fTerm->InitCheck() < B_OK) {
  1162. FATAL(("Corrupt tree in expression!\n"));
  1163. delete fTerm;
  1164. fTerm = NULL;
  1165. }
  1166. D(if (fTerm != NULL) {
  1167. fTerm->PrintToStream();
  1168. D(__out("\n"));
  1169. if (*expr != '\0')
  1170. PRINT(("Unexpected end of string: \"%s\"!\n", expr));
  1171. });
  1172. fPosition = expr;
  1173. }
  1174. Expression::~Expression()
  1175. {
  1176. delete fTerm;
  1177. }
  1178. Term *
  1179. Expression::ParseEquation(char **expr)
  1180. {
  1181. skipWhitespace(expr);
  1182. bool nott = false; // note: not is a C++ keyword
  1183. if (**expr == '!') {
  1184. skipWhitespace(expr, 1);
  1185. if (**expr != '(')
  1186. return NULL;
  1187. nott = true;
  1188. }
  1189. if (**expr == ')') {
  1190. // shouldn't be handled here
  1191. return NULL;
  1192. } else if (**expr == '(') {
  1193. skipWhitespace(expr, 1);
  1194. Term *term = ParseOr(expr);
  1195. skipWhitespace(expr);
  1196. if (**expr != ')') {
  1197. delete term;
  1198. return NULL;
  1199. }
  1200. // If the term is negated, we just complement the tree, to get
  1201. // rid of the not, a.k.a. DeMorgan's Law.
  1202. if (nott)
  1203. term->Complement();
  1204. skipWhitespace(expr, 1);
  1205. return term;
  1206. }
  1207. Equation *equation = new Equation(expr);
  1208. if (equation == NULL || equation->InitCheck() < B_OK) {
  1209. delete equation;
  1210. return NULL;
  1211. }
  1212. return equation;
  1213. }
  1214. Term *
  1215. Expression::ParseAnd(char **expr)
  1216. {
  1217. Term *left = ParseEquation(expr);
  1218. if (left == NULL)
  1219. return NULL;
  1220. while (IsOperator(expr,'&')) {
  1221. Term *right = ParseAnd(expr);
  1222. Term *newParent = NULL;
  1223. if (right == NULL || (newParent = new Operator(left, OP_AND, right)) == NULL) {
  1224. delete left;
  1225. delete right;
  1226. return NULL;
  1227. }
  1228. left = newParent;
  1229. }
  1230. return left;
  1231. }
  1232. Term *
  1233. Expression::ParseOr(char **expr)
  1234. {
  1235. Term *left = ParseAnd(expr);
  1236. if (left == NULL)
  1237. return NULL;
  1238. while (IsOperator(expr,'|')) {
  1239. Term *right = ParseAnd(expr);
  1240. Term *newParent = NULL;
  1241. if (right == NULL || (newParent = new Operator(left, OP_OR, right)) == NULL) {
  1242. delete left;
  1243. delete right;
  1244. return NULL;
  1245. }
  1246. left = newParent;
  1247. }
  1248. return left;
  1249. }
  1250. bool
  1251. Expression::IsOperator(char **expr, char op)
  1252. {
  1253. char *string = *expr;
  1254. if (*string == op && *(string + 1) == op) {
  1255. *expr += 2;
  1256. return true;
  1257. }
  1258. return false;
  1259. }
  1260. status_t
  1261. Expression::InitCheck()
  1262. {
  1263. if (fTerm == NULL)
  1264. return B_BAD_VALUE;
  1265. return B_OK;
  1266. }
  1267. // #pragma mark -
  1268. Query::Query(Volume *volume, Expression *expression, uint32 flags)
  1269. :
  1270. fVolume(volume),
  1271. fExpression(expression),
  1272. fCurrent(NULL),
  1273. fIterator(NULL),
  1274. fIndex(volume),
  1275. fFlags(flags),
  1276. fPort(-1),
  1277. fNeedsEntry(false)
  1278. {
  1279. // if the expression has a valid root pointer, the whole tree has
  1280. // already passed the sanity check, so that we don't have to check
  1281. // every pointer
  1282. if (volume == NULL || expression == NULL || expression->Root() == NULL)
  1283. return;
  1284. // create index on the stack and delete it afterwards
  1285. fExpression->Root()->CalculateScore(fIndex);
  1286. fIndex.Unset();
  1287. fNeedsEntry = fExpression->Root()->NeedsEntry();
  1288. Rewind();
  1289. if (fFlags & B_LIVE_QUERY)
  1290. volume->AddQuery(this);
  1291. }
  1292. Query::~Query()
  1293. {
  1294. if (fFlags & B_LIVE_QUERY)
  1295. fVolume->RemoveQuery(this);
  1296. }
  1297. status_t
  1298. Query::Rewind()
  1299. {
  1300. // free previous stuff
  1301. fStack.MakeEmpty();
  1302. delete fIterator;
  1303. fIterator = NULL;
  1304. fCurrent = NULL;
  1305. // put the whole expression on the stack
  1306. Stack<Term *> stack;
  1307. stack.Push(fExpression->Root());
  1308. Term *term;
  1309. while (stack.Pop(&term)) {
  1310. if (term->Op() < OP_EQUATION) {
  1311. Operator *op = (Operator *)term;
  1312. if (op->Op() == OP_OR) {
  1313. stack.Push(op->Left());
  1314. stack.Push(op->Right());
  1315. } else {
  1316. // For OP_AND, we can use the scoring system to decide which path to add
  1317. if (op->Right()->Score() > op->Left()->Score())
  1318. stack.Push(op->Right());
  1319. else
  1320. stack.Push(op->Left());
  1321. }
  1322. } else if (term->Op() == OP_EQUATION || fStack.Push((Equation *)term) < B_OK)
  1323. FATAL(("Unknown term on stack or stack error"));
  1324. }
  1325. return B_OK;
  1326. }
  1327. status_t
  1328. Query::GetNextEntry(struct dirent *dirent, size_t size)
  1329. {
  1330. // If we don't have an equation to use yet/anymore, get a new one
  1331. // from the stack
  1332. while (true) {
  1333. if (fIterator == NULL) {
  1334. if (!fStack.Pop(&fCurrent)
  1335. || fCurrent == NULL
  1336. || fCurrent->PrepareQuery(fVolume, fIndex, &fIterator,
  1337. fFlags & B_QUERY_NON_INDEXED) < B_OK)
  1338. return B_ENTRY_NOT_FOUND;
  1339. }
  1340. if (fCurrent == NULL)
  1341. RETURN_ERROR(B_ERROR);
  1342. status_t status = fCurrent->GetNextMatching(fVolume, fIterator, dirent, size);
  1343. if (status < B_OK) {
  1344. delete fIterator;
  1345. fIterator = NULL;
  1346. fCurrent = NULL;
  1347. } else {
  1348. // only return if we have another entry
  1349. return B_OK;
  1350. }
  1351. }
  1352. }
  1353. void
  1354. Query::SetLiveMode(port_id port, int32 token)
  1355. {
  1356. fPort = port;
  1357. fToken = token;
  1358. if ((fFlags & B_LIVE_QUERY) == 0) {
  1359. // you can decide at any point to set the live query mode,
  1360. // only live queries have to be updated by attribute changes
  1361. fFlags |= B_LIVE_QUERY;
  1362. fVolume->AddQuery(this);
  1363. }
  1364. }
  1365. void
  1366. Query::LiveUpdate(Entry *entry, Node* node, const char *attribute, int32 type,
  1367. const uint8 *oldKey, size_t oldLength, const uint8 *newKey,
  1368. size_t newLength)
  1369. {
  1370. PRINT(("%p->Query::LiveUpdate(%p, %p, \"%s\", 0x%lx, %p, %lu, %p, %lu)\n",
  1371. this, entry, node, attribute, type, oldKey, oldLength, newKey, newLength));
  1372. if (fPort < 0 || fExpression == NULL || node == NULL || attribute == NULL)
  1373. return;
  1374. // ToDo: check if the attribute is part of the query at all...
  1375. // If no entry has been supplied, but the we need one for the evaluation
  1376. // (i.e. the "name" attribute is used), we invoke ourselves for all entries
  1377. // referring to the given node.
  1378. if (!entry && fNeedsEntry) {
  1379. entry = node->GetFirstReferrer();
  1380. while (entry) {
  1381. LiveUpdate(entry, node, attribute, type, oldKey, oldLength, newKey,
  1382. newLength);
  1383. entry = node->GetNextReferrer(entry);
  1384. }
  1385. return;
  1386. }
  1387. status_t oldStatus = fExpression->Root()->Match(entry, node, attribute,
  1388. type, oldKey, oldLength);
  1389. status_t newStatus = fExpression->Root()->Match(entry, node, attribute,
  1390. type, newKey, newLength);
  1391. PRINT((" oldStatus: 0x%lx, newStatus: 0x%lx\n", oldStatus, newStatus));
  1392. int32 op;
  1393. if (oldStatus == MATCH_OK && newStatus == MATCH_OK) {
  1394. // only send out a notification if the name was changed
  1395. if (oldKey == NULL || strcmp(attribute,"name"))
  1396. return;
  1397. if (entry) {
  1398. // entry should actually always be given, when the changed
  1399. // attribute is the entry name
  1400. PRINT(("send_notification(): old: B_ENTRY_REMOVED\n"));
  1401. send_notification(fPort, fToken, B_QUERY_UPDATE, B_ENTRY_REMOVED,
  1402. fVolume->GetID(), 0, entry->GetParent()->GetID(), 0,
  1403. entry->GetNode()->GetID(), (const char *)oldKey);
  1404. }
  1405. op = B_ENTRY_CREATED;
  1406. } else if (oldStatus != MATCH_OK && newStatus != MATCH_OK) {
  1407. // nothing has changed
  1408. return;
  1409. } else if (oldStatus == MATCH_OK && newStatus != MATCH_OK)
  1410. op = B_ENTRY_REMOVED;
  1411. else
  1412. op = B_ENTRY_CREATED;
  1413. // We send a notification for the given entry, if any, or otherwise for
  1414. // all entries referring to the node;
  1415. if (entry) {
  1416. PRINT(("send_notification(): new: %s\n", (op == B_ENTRY_REMOVED ? "B_ENTRY_REMOVED" : "B_ENTRY_CREATED")));
  1417. send_notification(fPort, fToken, B_QUERY_UPDATE, op, fVolume->GetID(),
  1418. 0, entry->GetParent()->GetID(), 0, entry->GetNode()->GetID(),
  1419. entry->GetName());
  1420. } else {
  1421. entry = node->GetFirstReferrer();
  1422. while (entry) {
  1423. send_notification(fPort, fToken, B_QUERY_UPDATE, op,
  1424. fVolume->GetID(), 0, entry->GetParent()->GetID(), 0,
  1425. entry->GetNode()->GetID(), entry->GetName());
  1426. entry = node->GetNextReferrer(entry);
  1427. }
  1428. }
  1429. }