1 /* 2 Open Tracker License 3 4 Terms and Conditions 5 6 Copyright (c) 1991-2000, Be Incorporated. All rights reserved. 7 8 Permission is hereby granted, free of charge, to any person obtaining a copy of 9 this software and associated documentation files (the "Software"), to deal in 10 the Software without restriction, including without limitation the rights to 11 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 12 of the Software, and to permit persons to whom the Software is furnished to do 13 so, subject to the following conditions: 14 15 The above copyright notice and this permission notice applies to all licensees 16 and shall be included in all copies or substantial portions of the Software. 17 18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY, 20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 22 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION 23 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 25 Except as contained in this notice, the name of Be Incorporated shall not be 26 used in advertising or otherwise to promote the sale, use or other dealings in 27 this Software without prior written authorization from Be Incorporated. 28 29 Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks 30 of Be Incorporated in the United States and other countries. Other brand product 31 names are registered trademarks or trademarks of their respective holders. 32 All rights reserved. 33 */ 34 35 36 #include <Debug.h> 37 #include <Entry.h> 38 #include <ObjectList.h> 39 #include <Path.h> 40 41 #include <new> 42 #include <string.h> 43 44 #include "EntryIterator.h" 45 46 47 // #pragma mark - TWalkerWrapper 48 49 50 TWalkerWrapper::TWalkerWrapper(BTrackerPrivate::TWalker* walker) 51 : 52 fWalker(walker), 53 fStatus(B_OK) 54 { 55 } 56 57 58 TWalkerWrapper::~TWalkerWrapper() 59 { 60 delete fWalker; 61 } 62 63 64 status_t 65 TWalkerWrapper::InitCheck() const 66 { 67 return fStatus; 68 } 69 70 71 status_t 72 TWalkerWrapper::GetNextEntry(BEntry* entry, bool traverse) 73 { 74 fStatus = fWalker->GetNextEntry(entry, traverse); 75 76 return fStatus; 77 } 78 79 80 status_t 81 TWalkerWrapper::GetNextRef(entry_ref* ref) 82 { 83 fStatus = fWalker->GetNextRef(ref); 84 85 return fStatus; 86 } 87 88 89 int32 90 TWalkerWrapper::GetNextDirents(struct dirent* buffer, size_t length, 91 int32 count) 92 { 93 int32 result = fWalker->GetNextDirents(buffer, length, count); 94 fStatus = result < B_OK ? result : (result ? B_OK : B_ENTRY_NOT_FOUND); 95 96 return result; 97 } 98 99 100 status_t 101 TWalkerWrapper::Rewind() 102 { 103 return fWalker->Rewind(); 104 } 105 106 107 int32 108 TWalkerWrapper::CountEntries() 109 { 110 return fWalker->CountEntries(); 111 } 112 113 114 // #pragma mark - EntryListBase 115 116 117 EntryListBase::EntryListBase() 118 : 119 fStatus(B_OK) 120 { 121 } 122 123 124 status_t 125 EntryListBase::InitCheck() const 126 { 127 return fStatus; 128 } 129 130 131 dirent* 132 EntryListBase::Next(dirent* ent) 133 { 134 return (dirent*)((char*)ent + ent->d_reclen); 135 } 136 137 138 // #pragma mark - CachedEntryIterator 139 140 141 CachedEntryIterator::CachedEntryIterator(BEntryList* iterator, 142 int32 numEntries, bool sortInodes) 143 : 144 fIterator(iterator), 145 fEntryRefBuffer(NULL), 146 fCacheSize(numEntries), 147 fNumEntries(0), 148 fIndex(0), 149 fDirentBuffer(NULL), 150 fCurrentDirent(NULL), 151 fSortInodes(sortInodes), 152 fSortedList(NULL), 153 fEntryBuffer(NULL) 154 { 155 } 156 157 158 CachedEntryIterator::~CachedEntryIterator() 159 { 160 delete[] fEntryRefBuffer; 161 free(fDirentBuffer); 162 delete fSortedList; 163 delete[] fEntryBuffer; 164 } 165 166 167 status_t 168 CachedEntryIterator::GetNextEntry(BEntry* result, bool traverse) 169 { 170 ASSERT(fDirentBuffer == NULL); 171 ASSERT(fEntryRefBuffer == NULL); 172 173 if (fEntryBuffer == NULL) { 174 fEntryBuffer = new BEntry [fCacheSize]; 175 ASSERT(fIndex == 0 && fNumEntries == 0); 176 } 177 178 if (fIndex >= fNumEntries) { 179 // fill up the buffer or stop if error; keep error around 180 // and return it when appropriate 181 fStatus = B_OK; 182 for (fNumEntries = 0; fNumEntries < fCacheSize; fNumEntries++) { 183 fStatus = fIterator->GetNextEntry(&fEntryBuffer[fNumEntries], 184 traverse); 185 if (fStatus != B_OK) 186 break; 187 } 188 fIndex = 0; 189 } 190 191 *result = fEntryBuffer[fIndex++]; 192 if (fIndex > fNumEntries) { 193 // we are at the end of the cache we loaded up, time to return 194 // an error, if we had one 195 return fStatus; 196 } 197 198 return B_OK; 199 } 200 201 202 status_t 203 CachedEntryIterator::GetNextRef(entry_ref* ref) 204 { 205 ASSERT(fDirentBuffer == NULL); 206 ASSERT(fEntryBuffer == NULL); 207 208 if (fEntryRefBuffer == NULL) { 209 fEntryRefBuffer = new entry_ref[fCacheSize]; 210 ASSERT(fIndex == 0 && fNumEntries == 0); 211 } 212 213 if (fIndex >= fNumEntries) { 214 // fill up the buffer or stop if error; keep error around 215 // and return it when appropriate 216 fStatus = B_OK; 217 for (fNumEntries = 0; fNumEntries < fCacheSize; fNumEntries++) { 218 fStatus = fIterator->GetNextRef(&fEntryRefBuffer[fNumEntries]); 219 if (fStatus != B_OK) 220 break; 221 } 222 fIndex = 0; 223 } 224 225 *ref = fEntryRefBuffer[fIndex++]; 226 if (fIndex > fNumEntries) { 227 // we are at the end of the cache we loaded up, time to return 228 // an error, if we had one 229 return fStatus; 230 } 231 232 return B_OK; 233 } 234 235 236 /*static*/ int 237 CachedEntryIterator::_CompareInodes(const dirent* ent1, const dirent* ent2) 238 { 239 if (ent1->d_ino < ent2->d_ino) 240 return -1; 241 242 if (ent1->d_ino == ent2->d_ino) 243 return 0; 244 245 return 1; 246 } 247 248 249 int32 250 CachedEntryIterator::GetNextDirents(struct dirent* ent, size_t size, 251 int32 count) 252 { 253 ASSERT(fEntryRefBuffer == NULL); 254 if (fDirentBuffer == NULL) { 255 fDirentBuffer = (dirent*)malloc(kDirentBufferSize); 256 ASSERT(fIndex == 0 && fNumEntries == 0); 257 ASSERT(size > offsetof(struct dirent, d_name) + B_FILE_NAME_LENGTH); 258 } 259 260 if (count == 0) 261 return 0; 262 263 if (fIndex >= fNumEntries) { 264 // we are out of stock, cache em up 265 fCurrentDirent = fDirentBuffer; 266 int32 bufferRemain = kDirentBufferSize; 267 for (fNumEntries = 0; fNumEntries < fCacheSize; ) { 268 int32 count = fIterator->GetNextDirents(fCurrentDirent, 269 bufferRemain, 1); 270 271 if (count <= 0) 272 break; 273 274 fNumEntries += count; 275 276 int32 currentDirentSize = fCurrentDirent->d_reclen; 277 bufferRemain -= currentDirentSize; 278 ASSERT(bufferRemain >= 0); 279 280 if ((size_t)bufferRemain 281 < (offsetof(struct dirent, d_name) + B_FILE_NAME_LENGTH)) { 282 // cant fit a big entryRef in the buffer, just bail 283 // and start from scratch 284 break; 285 } 286 287 fCurrentDirent 288 = (dirent*)((char*)fCurrentDirent + currentDirentSize); 289 } 290 fCurrentDirent = fDirentBuffer; 291 if (fSortInodes) { 292 if (!fSortedList) 293 fSortedList = new BObjectList<dirent>(fCacheSize); 294 else 295 fSortedList->MakeEmpty(); 296 297 for (int32 count = 0; count < fNumEntries; count++) { 298 fSortedList->AddItem(fCurrentDirent, 0); 299 fCurrentDirent = Next(fCurrentDirent); 300 } 301 fSortedList->SortItems(&_CompareInodes); 302 fCurrentDirent = fDirentBuffer; 303 } 304 fIndex = 0; 305 } 306 if (fIndex >= fNumEntries) { 307 // we are done, no more dirents left 308 return 0; 309 } 310 311 if (fSortInodes) 312 fCurrentDirent = fSortedList->ItemAt(fIndex); 313 314 fIndex++; 315 uint32 currentDirentSize = fCurrentDirent->d_reclen; 316 ASSERT(currentDirentSize <= size); 317 if (currentDirentSize > size) 318 return 0; 319 320 memcpy(ent, fCurrentDirent, currentDirentSize); 321 322 if (!fSortInodes) 323 fCurrentDirent = (dirent*)((char*)fCurrentDirent + currentDirentSize); 324 325 return 1; 326 } 327 328 329 status_t 330 CachedEntryIterator::Rewind() 331 { 332 fIndex = 0; 333 fNumEntries = 0; 334 fCurrentDirent = NULL; 335 fStatus = B_OK; 336 337 delete fSortedList; 338 fSortedList = NULL; 339 340 return fIterator->Rewind(); 341 } 342 343 344 int32 345 CachedEntryIterator::CountEntries() 346 { 347 return fIterator->CountEntries(); 348 } 349 350 351 void 352 CachedEntryIterator::SetTo(BEntryList* iterator) 353 { 354 fIndex = 0; 355 fNumEntries = 0; 356 fStatus = B_OK; 357 fIterator = iterator; 358 } 359 360 361 // #pragma mark - CachedDirectoryEntryList 362 363 364 CachedDirectoryEntryList::CachedDirectoryEntryList(const BDirectory& directory) 365 : 366 CachedEntryIterator(0, 40, true), 367 fDirectory(directory) 368 { 369 fStatus = fDirectory.InitCheck(); 370 SetTo(&fDirectory); 371 } 372 373 374 CachedDirectoryEntryList::~CachedDirectoryEntryList() 375 { 376 } 377 378 379 // #pragma mark - DirectoryEntryList 380 381 382 DirectoryEntryList::DirectoryEntryList(const BDirectory& directory) 383 : 384 fDirectory(directory) 385 { 386 fStatus = fDirectory.InitCheck(); 387 } 388 389 390 status_t 391 DirectoryEntryList::GetNextEntry(BEntry* entry, bool traverse) 392 { 393 fStatus = fDirectory.GetNextEntry(entry, traverse); 394 return fStatus; 395 } 396 397 398 status_t 399 DirectoryEntryList::GetNextRef(entry_ref* ref) 400 { 401 fStatus = fDirectory.GetNextRef(ref); 402 return fStatus; 403 } 404 405 406 int32 407 DirectoryEntryList::GetNextDirents(struct dirent* buffer, size_t length, 408 int32 count) 409 { 410 fStatus = fDirectory.GetNextDirents(buffer, length, count); 411 return fStatus; 412 } 413 414 415 status_t 416 DirectoryEntryList::Rewind() 417 { 418 fStatus = fDirectory.Rewind(); 419 return fStatus; 420 } 421 422 423 int32 424 DirectoryEntryList::CountEntries() 425 { 426 return fDirectory.CountEntries(); 427 } 428 429 430 // #pragma mark - EntryIteratorList 431 432 433 EntryIteratorList::EntryIteratorList() 434 : 435 fList(5, true), 436 fCurrentIndex(0) 437 { 438 } 439 440 441 EntryIteratorList::~EntryIteratorList() 442 { 443 int32 count = fList.CountItems(); 444 for (;count; count--) { 445 // workaround for BEntryList not having a proper destructor 446 BEntryList* entry = fList.RemoveItemAt(count - 1); 447 EntryListBase* fixedEntry = dynamic_cast<EntryListBase*>(entry); 448 if (fixedEntry != NULL) 449 delete fixedEntry; 450 else 451 delete entry; 452 } 453 } 454 455 456 void 457 EntryIteratorList::AddItem(BEntryList* walker) 458 { 459 fList.AddItem(walker); 460 } 461 462 463 status_t 464 EntryIteratorList::GetNextEntry(BEntry* entry, bool traverse) 465 { 466 while (true) { 467 if (fCurrentIndex >= fList.CountItems()) { 468 fStatus = B_ENTRY_NOT_FOUND; 469 break; 470 } 471 472 fStatus = fList.ItemAt(fCurrentIndex)->GetNextEntry(entry, traverse); 473 if (fStatus != B_ENTRY_NOT_FOUND) 474 break; 475 476 fCurrentIndex++; 477 } 478 return fStatus; 479 } 480 481 482 status_t 483 EntryIteratorList::GetNextRef(entry_ref* ref) 484 { 485 while (true) { 486 if (fCurrentIndex >= fList.CountItems()) { 487 fStatus = B_ENTRY_NOT_FOUND; 488 break; 489 } 490 491 fStatus = fList.ItemAt(fCurrentIndex)->GetNextRef(ref); 492 if (fStatus != B_ENTRY_NOT_FOUND) 493 break; 494 495 fCurrentIndex++; 496 } 497 return fStatus; 498 } 499 500 501 int32 502 EntryIteratorList::GetNextDirents(struct dirent* buffer, size_t length, 503 int32 count) 504 { 505 int32 result = 0; 506 while (true) { 507 if (fCurrentIndex >= fList.CountItems()) { 508 fStatus = B_ENTRY_NOT_FOUND; 509 break; 510 } 511 512 result = fList.ItemAt(fCurrentIndex)->GetNextDirents(buffer, length, 513 count); 514 if (result > 0) { 515 fStatus = B_OK; 516 break; 517 } 518 519 fCurrentIndex++; 520 } 521 return result; 522 } 523 524 525 status_t 526 EntryIteratorList::Rewind() 527 { 528 fCurrentIndex = 0; 529 int32 count = fList.CountItems(); 530 for (int32 index = 0; index < count; index++) 531 fStatus = fList.ItemAt(index)->Rewind(); 532 533 return fStatus; 534 } 535 536 537 int32 538 EntryIteratorList::CountEntries() 539 { 540 int32 result = 0; 541 542 int32 count = fList.CountItems(); 543 for (int32 index = 0; index < count; index++) 544 result += fList.ItemAt(fCurrentIndex)->CountEntries(); 545 546 return result; 547 } 548 549 550 // #pragma mark - CachedEntryIteratorList 551 552 553 CachedEntryIteratorList::CachedEntryIteratorList(bool sortInodes) 554 : 555 CachedEntryIterator(NULL, 10, sortInodes) 556 { 557 fStatus = B_OK; 558 SetTo(&fIteratorList); 559 } 560 561 562 void 563 CachedEntryIteratorList::AddItem(BEntryList* walker) 564 { 565 fIteratorList.AddItem(walker); 566 } 567