1 /* 2 * Copyright 2002-2009, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Tyler Dauwalder 7 * Ingo Weinhold 8 * Axel Dörfler, axeld@pinc-software.de. 9 */ 10 11 12 #include <Query.h> 13 14 #include <fcntl.h> 15 #include <new> 16 #include <time.h> 17 18 #include <Entry.h> 19 #include <fs_query.h> 20 #include <parsedate.h> 21 #include <Volume.h> 22 23 #include <MessengerPrivate.h> 24 #include <syscalls.h> 25 #include <query_private.h> 26 27 #include "QueryPredicate.h" 28 #include "storage_support.h" 29 30 31 using namespace std; 32 using namespace BPrivate::Storage; 33 34 35 // Creates an uninitialized BQuery. 36 BQuery::BQuery() 37 : 38 BEntryList(), 39 fStack(NULL), 40 fPredicate(NULL), 41 fDevice((dev_t)B_ERROR), 42 fLive(false), 43 fPort(B_ERROR), 44 fToken(0), 45 fQueryFd(-1) 46 { 47 } 48 49 50 // Frees all resources associated with the object. 51 BQuery::~BQuery() 52 { 53 Clear(); 54 } 55 56 57 // Resets the object to a uninitialized state. 58 status_t 59 BQuery::Clear() 60 { 61 // close the currently open query 62 status_t error = B_OK; 63 if (fQueryFd >= 0) { 64 error = _kern_close(fQueryFd); 65 fQueryFd = -1; 66 } 67 // delete the predicate stack and the predicate 68 delete fStack; 69 fStack = NULL; 70 delete[] fPredicate; 71 fPredicate = NULL; 72 // reset the other parameters 73 fDevice = (dev_t)B_ERROR; 74 fLive = false; 75 fPort = B_ERROR; 76 fToken = 0; 77 return error; 78 } 79 80 81 // Pushes an attribute name onto the predicate stack. 82 status_t 83 BQuery::PushAttr(const char* attrName) 84 { 85 return _PushNode(new(nothrow) AttributeNode(attrName), true); 86 } 87 88 89 // Pushes an operator onto the predicate stack. 90 status_t 91 BQuery::PushOp(query_op op) 92 { 93 status_t error = B_OK; 94 switch (op) { 95 case B_EQ: 96 case B_GT: 97 case B_GE: 98 case B_LT: 99 case B_LE: 100 case B_NE: 101 case B_CONTAINS: 102 case B_BEGINS_WITH: 103 case B_ENDS_WITH: 104 case B_AND: 105 case B_OR: 106 error = _PushNode(new(nothrow) BinaryOpNode(op), true); 107 break; 108 case B_NOT: 109 error = _PushNode(new(nothrow) UnaryOpNode(op), true); 110 break; 111 default: 112 error = _PushNode(new(nothrow) SpecialOpNode(op), true); 113 break; 114 } 115 return error; 116 } 117 118 119 // Pushes a uint32 onto the predicate stack. 120 status_t 121 BQuery::PushUInt32(uint32 value) 122 { 123 return _PushNode(new(nothrow) UInt32ValueNode(value), true); 124 } 125 126 127 // Pushes an int32 onto the predicate stack. 128 status_t 129 BQuery::PushInt32(int32 value) 130 { 131 return _PushNode(new(nothrow) Int32ValueNode(value), true); 132 } 133 134 135 // Pushes a uint64 onto the predicate stack. 136 status_t 137 BQuery::PushUInt64(uint64 value) 138 { 139 return _PushNode(new(nothrow) UInt64ValueNode(value), true); 140 } 141 142 143 // Pushes an int64 onto the predicate stack. 144 status_t 145 BQuery::PushInt64(int64 value) 146 { 147 return _PushNode(new(nothrow) Int64ValueNode(value), true); 148 } 149 150 151 // Pushes a float onto the predicate stack. 152 status_t 153 BQuery::PushFloat(float value) 154 { 155 return _PushNode(new(nothrow) FloatValueNode(value), true); 156 } 157 158 159 // Pushes a double onto the predicate stack. 160 status_t 161 BQuery::PushDouble(double value) 162 { 163 return _PushNode(new(nothrow) DoubleValueNode(value), true); 164 } 165 166 167 // Pushes a string onto the predicate stack. 168 status_t 169 BQuery::PushString(const char* value, bool caseInsensitive) 170 { 171 return _PushNode(new(nothrow) StringNode(value, caseInsensitive), true); 172 } 173 174 175 // Pushes a date onto the predicate stack. 176 status_t 177 BQuery::PushDate(const char* date) 178 { 179 if (date == NULL || !date[0] || parsedate(date, time(NULL)) < 0) 180 return B_BAD_VALUE; 181 182 return _PushNode(new(nothrow) DateNode(date), true); 183 } 184 185 186 // Assigns a volume to the BQuery object. 187 status_t 188 BQuery::SetVolume(const BVolume* volume) 189 { 190 if (volume == NULL) 191 return B_BAD_VALUE; 192 if (_HasFetched()) 193 return B_NOT_ALLOWED; 194 195 if (volume->InitCheck() == B_OK) 196 fDevice = volume->Device(); 197 else 198 fDevice = (dev_t)B_ERROR; 199 200 return B_OK; 201 } 202 203 204 // Assigns the passed-in predicate expression. 205 status_t 206 BQuery::SetPredicate(const char* expression) 207 { 208 status_t error = (expression ? B_OK : B_BAD_VALUE); 209 if (error == B_OK && _HasFetched()) 210 error = B_NOT_ALLOWED; 211 if (error == B_OK) 212 error = _SetPredicate(expression); 213 return error; 214 } 215 216 217 // Assigns the target messenger and makes the query live. 218 status_t 219 BQuery::SetTarget(BMessenger messenger) 220 { 221 status_t error = (messenger.IsValid() ? B_OK : B_BAD_VALUE); 222 if (error == B_OK && _HasFetched()) 223 error = B_NOT_ALLOWED; 224 if (error == B_OK) { 225 BMessenger::Private messengerPrivate(messenger); 226 fPort = messengerPrivate.Port(); 227 fToken = (messengerPrivate.IsPreferredTarget() 228 ? -1 : messengerPrivate.Token()); 229 fLive = true; 230 } 231 return error; 232 } 233 234 235 // Gets whether the query associated with this object is live. 236 bool 237 BQuery::IsLive() const 238 { 239 return fLive; 240 } 241 242 243 // Fills out buffer with the predicate string assigned to the BQuery object. 244 status_t 245 BQuery::GetPredicate(char* buffer, size_t length) 246 { 247 status_t error = (buffer ? B_OK : B_BAD_VALUE); 248 if (error == B_OK) 249 _EvaluateStack(); 250 if (error == B_OK && !fPredicate) 251 error = B_NO_INIT; 252 if (error == B_OK && length <= strlen(fPredicate)) 253 error = B_BAD_VALUE; 254 if (error == B_OK) 255 strcpy(buffer, fPredicate); 256 return error; 257 } 258 259 260 // Fills out the passed-in BString object with the predicate string 261 // assigned to the BQuery object. 262 status_t 263 BQuery::GetPredicate(BString* predicate) 264 { 265 status_t error = (predicate ? B_OK : B_BAD_VALUE); 266 if (error == B_OK) 267 _EvaluateStack(); 268 if (error == B_OK && !fPredicate) 269 error = B_NO_INIT; 270 if (error == B_OK) 271 predicate->SetTo(fPredicate); 272 return error; 273 } 274 275 276 // Gets the length of the predicate string. 277 size_t 278 BQuery::PredicateLength() 279 { 280 status_t error = _EvaluateStack(); 281 if (error == B_OK && !fPredicate) 282 error = B_NO_INIT; 283 size_t size = 0; 284 if (error == B_OK) 285 size = strlen(fPredicate) + 1; 286 return size; 287 } 288 289 290 // Gets the device ID identifying the volume of the BQuery object. 291 dev_t 292 BQuery::TargetDevice() const 293 { 294 return fDevice; 295 } 296 297 298 // Start fetching entries satisfying the predicate. 299 status_t 300 BQuery::Fetch() 301 { 302 if (_HasFetched()) 303 return B_NOT_ALLOWED; 304 305 _EvaluateStack(); 306 307 if (!fPredicate || fDevice < 0) 308 return B_NO_INIT; 309 310 BString parsedPredicate; 311 _ParseDates(parsedPredicate); 312 313 fQueryFd = _kern_open_query(fDevice, parsedPredicate.String(), 314 parsedPredicate.Length(), fLive ? B_LIVE_QUERY : 0, fPort, fToken); 315 if (fQueryFd < 0) 316 return fQueryFd; 317 318 // set close on exec flag 319 fcntl(fQueryFd, F_SETFD, FD_CLOEXEC); 320 321 return B_OK; 322 } 323 324 325 // #pragma mark - BEntryList interface 326 327 328 // Fills out entry with the next entry traversing symlinks if traverse is true. 329 status_t 330 BQuery::GetNextEntry(BEntry* entry, bool traverse) 331 { 332 status_t error = (entry ? B_OK : B_BAD_VALUE); 333 if (error == B_OK) { 334 entry_ref ref; 335 error = GetNextRef(&ref); 336 if (error == B_OK) 337 error = entry->SetTo(&ref, traverse); 338 } 339 return error; 340 } 341 342 343 // Fills out ref with the next entry as an entry_ref. 344 status_t 345 BQuery::GetNextRef(entry_ref* ref) 346 { 347 status_t error = (ref ? B_OK : B_BAD_VALUE); 348 if (error == B_OK && !_HasFetched()) 349 error = B_FILE_ERROR; 350 if (error == B_OK) { 351 BPrivate::Storage::LongDirEntry entry; 352 bool next = true; 353 while (error == B_OK && next) { 354 if (GetNextDirents(&entry, sizeof(entry), 1) != 1) { 355 error = B_ENTRY_NOT_FOUND; 356 } else { 357 next = (!strcmp(entry.d_name, ".") 358 || !strcmp(entry.d_name, "..")); 359 } 360 } 361 if (error == B_OK) { 362 ref->device = entry.d_pdev; 363 ref->directory = entry.d_pino; 364 error = ref->set_name(entry.d_name); 365 } 366 } 367 return error; 368 } 369 370 371 // Fill out up to count entries into the array of dirent structs pointed 372 // to by buffer. 373 int32 374 BQuery::GetNextDirents(struct dirent* buffer, size_t length, int32 count) 375 { 376 if (!buffer) 377 return B_BAD_VALUE; 378 if (!_HasFetched()) 379 return B_FILE_ERROR; 380 return _kern_read_dir(fQueryFd, buffer, length, count); 381 } 382 383 384 // Rewinds the entry list back to the first entry. 385 status_t 386 BQuery::Rewind() 387 { 388 if (!_HasFetched()) 389 return B_FILE_ERROR; 390 return _kern_rewind_dir(fQueryFd); 391 } 392 393 394 // Unimplemented method of the BEntryList interface. 395 int32 396 BQuery::CountEntries() 397 { 398 return B_ERROR; 399 } 400 401 402 /*! Gets whether Fetch() has already been called on this object. 403 404 \return \c true, if Fetch() was already called, \c false otherwise. 405 */ 406 bool 407 BQuery::_HasFetched() const 408 { 409 return fQueryFd >= 0; 410 } 411 412 413 /*! Pushes a node onto the predicate stack. 414 415 If the stack has not been allocate until this time, this method does 416 allocate it. 417 418 If the supplied node is \c NULL, it is assumed that there was not enough 419 memory to allocate the node and thus \c B_NO_MEMORY is returned. 420 421 In case the method fails, the caller retains the ownership of the supplied 422 node and thus is responsible for deleting it, if \a deleteOnError is 423 \c false. If it is \c true, the node is deleted, if an error occurs. 424 425 \param node The node to push. 426 \param deleteOnError Whether or not to delete the node if an error occurs. 427 428 \return A status code. 429 \retval B_OK Everything went fine. 430 \retval B_NO_MEMORY \a node was \c NULL or there was insufficient memory to 431 allocate the predicate stack or push the node. 432 \retval B_NOT_ALLOWED _PushNode() was called after Fetch(). 433 */ 434 status_t 435 BQuery::_PushNode(QueryNode* node, bool deleteOnError) 436 { 437 status_t error = (node ? B_OK : B_NO_MEMORY); 438 if (error == B_OK && _HasFetched()) 439 error = B_NOT_ALLOWED; 440 // allocate the stack, if necessary 441 if (error == B_OK && !fStack) { 442 fStack = new(nothrow) QueryStack; 443 if (!fStack) 444 error = B_NO_MEMORY; 445 } 446 if (error == B_OK) 447 error = fStack->PushNode(node); 448 if (error != B_OK && deleteOnError) 449 delete node; 450 return error; 451 } 452 453 454 /*! Helper method to set the predicate. 455 456 Does not check whether Fetch() has already been invoked. 457 458 \param expression The predicate string to set. 459 460 \return A status code. 461 \retval B_OK Everything went fine. 462 \retval B_NO_MEMORY There was insufficient memory to store the predicate. 463 */ 464 status_t 465 BQuery::_SetPredicate(const char* expression) 466 { 467 status_t error = B_OK; 468 // unset the old predicate 469 delete[] fPredicate; 470 fPredicate = NULL; 471 // set the new one 472 if (expression) { 473 fPredicate = new(nothrow) char[strlen(expression) + 1]; 474 if (fPredicate) 475 strcpy(fPredicate, expression); 476 else 477 error = B_NO_MEMORY; 478 } 479 return error; 480 } 481 482 483 /*! Evaluates the predicate stack. 484 485 The method does nothing (and returns \c B_OK), if the stack is \c NULL. 486 If the stack is not \c null and Fetch() has already been called, this 487 method fails. 488 489 \return A status code. 490 \retval B_OK Everything went fine. 491 \retval B_NO_MEMORY There was insufficient memory. 492 \retval B_NOT_ALLOWED _EvaluateStack() was called after Fetch(). 493 */ 494 status_t 495 BQuery::_EvaluateStack() 496 { 497 status_t error = B_OK; 498 if (fStack) { 499 _SetPredicate(NULL); 500 if (_HasFetched()) 501 error = B_NOT_ALLOWED; 502 // convert the stack to a tree and evaluate it 503 QueryNode* node = NULL; 504 if (error == B_OK) 505 error = fStack->ConvertToTree(node); 506 BString predicate; 507 if (error == B_OK) 508 error = node->GetString(predicate); 509 if (error == B_OK) 510 error = _SetPredicate(predicate.String()); 511 delete fStack; 512 fStack = NULL; 513 } 514 return error; 515 } 516 517 518 /*! Fills out \a parsedPredicate with a parsed predicate string. 519 520 \param parsedPredicate The predicate string to fill out. 521 */ 522 void 523 BQuery::_ParseDates(BString& parsedPredicate) 524 { 525 const char* start = fPredicate; 526 const char* pos = start; 527 bool quotes = false; 528 529 while (pos[0]) { 530 if (pos[0] == '\\') { 531 pos++; 532 continue; 533 } 534 if (pos[0] == '"') 535 quotes = !quotes; 536 else if (!quotes && pos[0] == '%') { 537 const char* end = strchr(pos + 1, '%'); 538 if (end == NULL) 539 continue; 540 541 parsedPredicate.Append(start, pos - start); 542 start = end + 1; 543 544 // We have a date string 545 BString date(pos + 1, start - 1 - pos); 546 parsedPredicate << parsedate(date.String(), time(NULL)); 547 548 pos = end; 549 } 550 pos++; 551 } 552 553 parsedPredicate.Append(start, pos - start); 554 } 555 556 557 // FBC 558 void BQuery::_QwertyQuery1() {} 559 void BQuery::_QwertyQuery2() {} 560 void BQuery::_QwertyQuery3() {} 561 void BQuery::_QwertyQuery4() {} 562 void BQuery::_QwertyQuery5() {} 563 void BQuery::_QwertyQuery6() {} 564 565