PageRenderTime 60ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/src/add-ons/kernel/file_systems/ramfs/Query.cpp

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