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 longEntry; 352 struct dirent* entry = longEntry.dirent(); 353 bool next = true; 354 while (error == B_OK && next) { 355 if (GetNextDirents(entry, sizeof(longEntry), 1) != 1) { 356 error = B_ENTRY_NOT_FOUND; 357 } else { 358 next = (!strcmp(entry->d_name, ".") 359 || !strcmp(entry->d_name, "..")); 360 } 361 } 362 if (error == B_OK) { 363 ref->device = entry->d_pdev; 364 ref->directory = entry->d_pino; 365 error = ref->set_name(entry->d_name); 366 } 367 } 368 return error; 369 } 370 371 372 // Fill out up to count entries into the array of dirent structs pointed 373 // to by buffer. 374 int32 375 BQuery::GetNextDirents(struct dirent* buffer, size_t length, int32 count) 376 { 377 if (!buffer) 378 return B_BAD_VALUE; 379 if (!_HasFetched()) 380 return B_FILE_ERROR; 381 return _kern_read_dir(fQueryFd, buffer, length, count); 382 } 383 384 385 // Rewinds the entry list back to the first entry. 386 status_t 387 BQuery::Rewind() 388 { 389 if (!_HasFetched()) 390 return B_FILE_ERROR; 391 return _kern_rewind_dir(fQueryFd); 392 } 393 394 395 // Unimplemented method of the BEntryList interface. 396 int32 397 BQuery::CountEntries() 398 { 399 return B_ERROR; 400 } 401 402 403 /*! Gets whether Fetch() has already been called on this object. 404 405 \return \c true, if Fetch() was already called, \c false otherwise. 406 */ 407 bool 408 BQuery::_HasFetched() const 409 { 410 return fQueryFd >= 0; 411 } 412 413 414 /*! Pushes a node onto the predicate stack. 415 416 If the stack has not been allocate until this time, this method does 417 allocate it. 418 419 If the supplied node is \c NULL, it is assumed that there was not enough 420 memory to allocate the node and thus \c B_NO_MEMORY is returned. 421 422 In case the method fails, the caller retains the ownership of the supplied 423 node and thus is responsible for deleting it, if \a deleteOnError is 424 \c false. If it is \c true, the node is deleted, if an error occurs. 425 426 \param node The node to push. 427 \param deleteOnError Whether or not to delete the node if an error occurs. 428 429 \return A status code. 430 \retval B_OK Everything went fine. 431 \retval B_NO_MEMORY \a node was \c NULL or there was insufficient memory to 432 allocate the predicate stack or push the node. 433 \retval B_NOT_ALLOWED _PushNode() was called after Fetch(). 434 */ 435 status_t 436 BQuery::_PushNode(QueryNode* node, bool deleteOnError) 437 { 438 status_t error = (node ? B_OK : B_NO_MEMORY); 439 if (error == B_OK && _HasFetched()) 440 error = B_NOT_ALLOWED; 441 // allocate the stack, if necessary 442 if (error == B_OK && !fStack) { 443 fStack = new(nothrow) QueryStack; 444 if (!fStack) 445 error = B_NO_MEMORY; 446 } 447 if (error == B_OK) 448 error = fStack->PushNode(node); 449 if (error != B_OK && deleteOnError) 450 delete node; 451 return error; 452 } 453 454 455 /*! Helper method to set the predicate. 456 457 Does not check whether Fetch() has already been invoked. 458 459 \param expression The predicate string to set. 460 461 \return A status code. 462 \retval B_OK Everything went fine. 463 \retval B_NO_MEMORY There was insufficient memory to store the predicate. 464 */ 465 status_t 466 BQuery::_SetPredicate(const char* expression) 467 { 468 status_t error = B_OK; 469 // unset the old predicate 470 delete[] fPredicate; 471 fPredicate = NULL; 472 // set the new one 473 if (expression) { 474 fPredicate = new(nothrow) char[strlen(expression) + 1]; 475 if (fPredicate) 476 strcpy(fPredicate, expression); 477 else 478 error = B_NO_MEMORY; 479 } 480 return error; 481 } 482 483 484 /*! Evaluates the predicate stack. 485 486 The method does nothing (and returns \c B_OK), if the stack is \c NULL. 487 If the stack is not \c null and Fetch() has already been called, this 488 method fails. 489 490 \return A status code. 491 \retval B_OK Everything went fine. 492 \retval B_NO_MEMORY There was insufficient memory. 493 \retval B_NOT_ALLOWED _EvaluateStack() was called after Fetch(). 494 */ 495 status_t 496 BQuery::_EvaluateStack() 497 { 498 status_t error = B_OK; 499 if (fStack) { 500 _SetPredicate(NULL); 501 if (_HasFetched()) 502 error = B_NOT_ALLOWED; 503 // convert the stack to a tree and evaluate it 504 QueryNode* node = NULL; 505 if (error == B_OK) 506 error = fStack->ConvertToTree(node); 507 BString predicate; 508 if (error == B_OK) 509 error = node->GetString(predicate); 510 if (error == B_OK) 511 error = _SetPredicate(predicate.String()); 512 delete fStack; 513 fStack = NULL; 514 } 515 return error; 516 } 517 518 519 /*! Fills out \a parsedPredicate with a parsed predicate string. 520 521 \param parsedPredicate The predicate string to fill out. 522 */ 523 void 524 BQuery::_ParseDates(BString& parsedPredicate) 525 { 526 const char* start = fPredicate; 527 const char* pos = start; 528 bool quotes = false; 529 530 while (pos[0]) { 531 if (pos[0] == '\\') { 532 pos++; 533 continue; 534 } 535 if (pos[0] == '"') 536 quotes = !quotes; 537 else if (!quotes && pos[0] == '%') { 538 const char* end = strchr(pos + 1, '%'); 539 if (end == NULL) 540 continue; 541 542 parsedPredicate.Append(start, pos - start); 543 start = end + 1; 544 545 // We have a date string 546 BString date(pos + 1, start - 1 - pos); 547 parsedPredicate << parsedate(date.String(), time(NULL)); 548 549 pos = end; 550 } 551 pos++; 552 } 553 554 parsedPredicate.Append(start, pos - start); 555 } 556 557 558 // FBC 559 void BQuery::_QwertyQuery1() {} 560 void BQuery::_QwertyQuery2() {} 561 void BQuery::_QwertyQuery3() {} 562 void BQuery::_QwertyQuery4() {} 563 void BQuery::_QwertyQuery5() {} 564 void BQuery::_QwertyQuery6() {} 565 566