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 bool 404 BQuery::_HasFetched() const 405 { 406 return fQueryFd >= 0; 407 } 408 409 410 // Pushes a node onto the predicate stack. 411 status_t 412 BQuery::_PushNode(QueryNode* node, bool deleteOnError) 413 { 414 status_t error = (node ? B_OK : B_NO_MEMORY); 415 if (error == B_OK && _HasFetched()) 416 error = B_NOT_ALLOWED; 417 // allocate the stack, if necessary 418 if (error == B_OK && !fStack) { 419 fStack = new(nothrow) QueryStack; 420 if (!fStack) 421 error = B_NO_MEMORY; 422 } 423 if (error == B_OK) 424 error = fStack->PushNode(node); 425 if (error != B_OK && deleteOnError) 426 delete node; 427 return error; 428 } 429 430 431 // Helper method to set the predicate. 432 status_t 433 BQuery::_SetPredicate(const char* expression) 434 { 435 status_t error = B_OK; 436 // unset the old predicate 437 delete[] fPredicate; 438 fPredicate = NULL; 439 // set the new one 440 if (expression) { 441 fPredicate = new(nothrow) char[strlen(expression) + 1]; 442 if (fPredicate) 443 strcpy(fPredicate, expression); 444 else 445 error = B_NO_MEMORY; 446 } 447 return error; 448 } 449 450 451 // Evaluates the predicate stack. 452 status_t 453 BQuery::_EvaluateStack() 454 { 455 status_t error = B_OK; 456 if (fStack) { 457 _SetPredicate(NULL); 458 if (_HasFetched()) 459 error = B_NOT_ALLOWED; 460 // convert the stack to a tree and evaluate it 461 QueryNode* node = NULL; 462 if (error == B_OK) 463 error = fStack->ConvertToTree(node); 464 BString predicate; 465 if (error == B_OK) 466 error = node->GetString(predicate); 467 if (error == B_OK) 468 error = _SetPredicate(predicate.String()); 469 delete fStack; 470 fStack = NULL; 471 } 472 return error; 473 } 474 475 476 void 477 BQuery::_ParseDates(BString& parsedPredicate) 478 { 479 const char* start = fPredicate; 480 const char* pos = start; 481 bool quotes = false; 482 483 while (pos[0]) { 484 if (pos[0] == '\\') { 485 pos++; 486 continue; 487 } 488 if (pos[0] == '"') 489 quotes = !quotes; 490 else if (!quotes && pos[0] == '%') { 491 const char* end = strchr(pos + 1, '%'); 492 if (end == NULL) 493 continue; 494 495 parsedPredicate.Append(start, pos - start); 496 start = end + 1; 497 498 // We have a date string 499 BString date(pos + 1, start - 1 - pos); 500 parsedPredicate << parsedate(date.String(), time(NULL)); 501 502 pos = end; 503 } 504 pos++; 505 } 506 507 parsedPredicate.Append(start, pos - start); 508 } 509 510 511 // FBC 512 void BQuery::_QwertyQuery1() {} 513 void BQuery::_QwertyQuery2() {} 514 void BQuery::_QwertyQuery3() {} 515 void BQuery::_QwertyQuery4() {} 516 void BQuery::_QwertyQuery5() {} 517 void BQuery::_QwertyQuery6() {} 518 519