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 #include <Debug.h> 36 #include <Entry.h> 37 #include <Path.h> 38 39 #include <new> 40 #include <string.h> 41 42 #include "EntryIterator.h" 43 #include "NodeWalker.h" 44 #include "ObjectList.h" 45 46 47 TWalkerWrapper::TWalkerWrapper(BTrackerPrivate::TWalker* walker) 48 : 49 fWalker(walker), 50 fStatus(B_OK) 51 { 52 } 53 54 55 TWalkerWrapper::~TWalkerWrapper() 56 { 57 delete fWalker; 58 } 59 60 61 status_t 62 TWalkerWrapper::InitCheck() const 63 { 64 return fStatus; 65 } 66 67 68 status_t 69 TWalkerWrapper::GetNextEntry(BEntry* entry, bool traverse) 70 { 71 fStatus = fWalker->GetNextEntry(entry, traverse); 72 return fStatus; 73 } 74 75 76 status_t 77 TWalkerWrapper::GetNextRef(entry_ref* ref) 78 { 79 fStatus = fWalker->GetNextRef(ref); 80 return fStatus; 81 } 82 83 84 int32 85 TWalkerWrapper::GetNextDirents(struct dirent* buffer, size_t length, 86 int32 count) 87 { 88 int32 result = fWalker->GetNextDirents(buffer, length, count); 89 fStatus = result < B_OK ? result : (result ? B_OK : B_ENTRY_NOT_FOUND); 90 return result; 91 } 92 93 94 status_t 95 TWalkerWrapper::Rewind() 96 { 97 return fWalker->Rewind(); 98 } 99 100 101 int32 102 TWalkerWrapper::CountEntries() 103 { 104 return fWalker->CountEntries(); 105 } 106 107 108 // #pragma mark - 109 110 111 EntryListBase::EntryListBase() 112 : fStatus(B_OK) 113 { 114 } 115 116 117 status_t 118 EntryListBase::InitCheck() const 119 { 120 return fStatus; 121 } 122 123 124 dirent* 125 EntryListBase::Next(dirent* ent) 126 { 127 return (dirent*)((char*)ent + ent->d_reclen); 128 } 129 130 131 // #pragma mark - 132 133 134 CachedEntryIterator::CachedEntryIterator(BEntryList* iterator, 135 int32 numEntries, bool sortInodes) 136 : 137 fIterator(iterator), 138 fEntryRefBuffer(NULL), 139 fCacheSize(numEntries), 140 fNumEntries(0), 141 fIndex(0), 142 fDirentBuffer(NULL), 143 fCurrentDirent(NULL), 144 fSortInodes(sortInodes), 145 fSortedList(NULL), 146 fEntryBuffer(NULL) 147 { 148 } 149 150 151 CachedEntryIterator::~CachedEntryIterator() 152 { 153 delete[] fEntryRefBuffer; 154 free(fDirentBuffer); 155 delete fSortedList; 156 delete[] fEntryBuffer; 157 } 158 159 160 status_t 161 CachedEntryIterator::GetNextEntry(BEntry* result, bool traverse) 162 { 163 ASSERT(!fDirentBuffer); 164 ASSERT(!fEntryRefBuffer); 165 166 if (!fEntryBuffer) { 167 fEntryBuffer = new BEntry [fCacheSize]; 168 ASSERT(fIndex == 0 && fNumEntries == 0); 169 } 170 if (fIndex >= fNumEntries) { 171 // fill up the buffer or stop if error; keep error around 172 // and return it when appropriate 173 fStatus = B_OK; 174 for (fNumEntries = 0; fNumEntries < fCacheSize; fNumEntries++) { 175 fStatus = fIterator->GetNextEntry(&fEntryBuffer[fNumEntries], 176 traverse); 177 if (fStatus != B_OK) 178 break; 179 } 180 fIndex = 0; 181 } 182 *result = fEntryBuffer[fIndex++]; 183 if (fIndex > fNumEntries) { 184 // we are at the end of the cache we loaded up, time to return 185 // an error, if we had one 186 return fStatus; 187 } 188 189 return B_OK; 190 } 191 192 193 status_t 194 CachedEntryIterator::GetNextRef(entry_ref* ref) 195 { 196 ASSERT(!fDirentBuffer); 197 ASSERT(!fEntryBuffer); 198 199 if (!fEntryRefBuffer) { 200 fEntryRefBuffer = new entry_ref[fCacheSize]; 201 ASSERT(fIndex == 0 && fNumEntries == 0); 202 } 203 204 if (fIndex >= fNumEntries) { 205 // fill up the buffer or stop if error; keep error around 206 // and return it when appropriate 207 fStatus = B_OK; 208 for (fNumEntries = 0; fNumEntries < fCacheSize; fNumEntries++) { 209 fStatus = fIterator->GetNextRef(&fEntryRefBuffer[fNumEntries]); 210 if (fStatus != B_OK) 211 break; 212 } 213 fIndex = 0; 214 } 215 *ref = fEntryRefBuffer[fIndex++]; 216 if (fIndex > fNumEntries) 217 // we are at the end of the cache we loaded up, time to return 218 // an error, if we had one 219 return fStatus; 220 221 return B_OK; 222 } 223 224 225 /*static*/ int 226 CachedEntryIterator::_CompareInodes(const dirent* ent1, const dirent* ent2) 227 { 228 if (ent1->d_ino < ent2->d_ino) 229 return -1; 230 if (ent1->d_ino == ent2->d_ino) 231 return 0; 232 233 return 1; 234 } 235 236 237 int32 238 CachedEntryIterator::GetNextDirents(struct dirent* ent, size_t size, 239 int32 count) 240 { 241 ASSERT(!fEntryRefBuffer); 242 if (!fDirentBuffer) { 243 fDirentBuffer = (dirent*)malloc(kDirentBufferSize); 244 ASSERT(fIndex == 0 && fNumEntries == 0); 245 ASSERT(size > sizeof(dirent) + B_FILE_NAME_LENGTH); 246 } 247 248 if (!count) 249 return 0; 250 251 if (fIndex >= fNumEntries) { 252 // we are out of stock, cache em up 253 fCurrentDirent = fDirentBuffer; 254 int32 bufferRemain = kDirentBufferSize; 255 for (fNumEntries = 0; fNumEntries < fCacheSize; ) { 256 int32 count = fIterator->GetNextDirents(fCurrentDirent, 257 bufferRemain, 1); 258 259 if (count <= 0) 260 break; 261 262 fNumEntries += count; 263 264 int32 currentDirentSize = fCurrentDirent->d_reclen; 265 bufferRemain -= currentDirentSize; 266 ASSERT(bufferRemain >= 0); 267 268 if ((size_t)bufferRemain 269 < (sizeof(dirent) + B_FILE_NAME_LENGTH)) { 270 // cant fit a big entryRef in the buffer, just bail 271 // and start from scratch 272 break; 273 } 274 275 fCurrentDirent 276 = (dirent*)((char*)fCurrentDirent + currentDirentSize); 277 } 278 fCurrentDirent = fDirentBuffer; 279 if (fSortInodes) { 280 if (!fSortedList) 281 fSortedList = new BObjectList<dirent>(fCacheSize); 282 else 283 fSortedList->MakeEmpty(); 284 285 for (int32 count = 0; count < fNumEntries; count++) { 286 fSortedList->AddItem(fCurrentDirent, 0); 287 fCurrentDirent = Next(fCurrentDirent); 288 } 289 fSortedList->SortItems(&_CompareInodes); 290 fCurrentDirent = fDirentBuffer; 291 } 292 fIndex = 0; 293 } 294 if (fIndex >= fNumEntries) { 295 // we are done, no more dirents left 296 return 0; 297 } 298 299 if (fSortInodes) 300 fCurrentDirent = fSortedList->ItemAt(fIndex); 301 302 fIndex++; 303 uint32 currentDirentSize = fCurrentDirent->d_reclen; 304 ASSERT(currentDirentSize <= size); 305 if (currentDirentSize > size) 306 return 0; 307 308 memcpy(ent, fCurrentDirent, currentDirentSize); 309 310 if (!fSortInodes) 311 fCurrentDirent = (dirent*)((char*)fCurrentDirent + currentDirentSize); 312 313 return 1; 314 } 315 316 317 status_t 318 CachedEntryIterator::Rewind() 319 { 320 fIndex = 0; 321 fNumEntries = 0; 322 fCurrentDirent = NULL; 323 fStatus = B_OK; 324 325 delete fSortedList; 326 fSortedList = NULL; 327 328 return fIterator->Rewind(); 329 } 330 331 332 int32 333 CachedEntryIterator::CountEntries() 334 { 335 return fIterator->CountEntries(); 336 } 337 338 339 void 340 CachedEntryIterator::SetTo(BEntryList* iterator) 341 { 342 fIndex = 0; 343 fNumEntries = 0; 344 fStatus = B_OK; 345 fIterator = iterator; 346 } 347 348 349 // #pragma mark - 350 351 352 CachedDirectoryEntryList::CachedDirectoryEntryList(const BDirectory &dir) 353 : CachedEntryIterator(0, 40, true), 354 fDir(dir) 355 { 356 fStatus = fDir.InitCheck(); 357 SetTo(&fDir); 358 } 359 360 361 CachedDirectoryEntryList::~CachedDirectoryEntryList() 362 { 363 } 364 365 366 // #pragma mark - 367 368 369 DirectoryEntryList::DirectoryEntryList(const BDirectory &dir) 370 : 371 fDir(dir) 372 { 373 fStatus = fDir.InitCheck(); 374 } 375 376 377 status_t 378 DirectoryEntryList::GetNextEntry(BEntry* entry, bool traverse) 379 { 380 fStatus = fDir.GetNextEntry(entry, traverse); 381 return fStatus; 382 } 383 384 385 status_t 386 DirectoryEntryList::GetNextRef(entry_ref* ref) 387 { 388 fStatus = fDir.GetNextRef(ref); 389 return fStatus; 390 } 391 392 393 int32 394 DirectoryEntryList::GetNextDirents(struct dirent* buffer, size_t length, 395 int32 count) 396 { 397 fStatus = fDir.GetNextDirents(buffer, length, count); 398 return fStatus; 399 } 400 401 402 status_t 403 DirectoryEntryList::Rewind() 404 { 405 fStatus = fDir.Rewind(); 406 return fStatus; 407 } 408 409 410 int32 411 DirectoryEntryList::CountEntries() 412 { 413 return fDir.CountEntries(); 414 } 415 416 417 // #pragma mark - 418 419 420 EntryIteratorList::EntryIteratorList() 421 : 422 fList(5, true), 423 fCurrentIndex(0) 424 { 425 } 426 427 428 EntryIteratorList::~EntryIteratorList() 429 { 430 int32 count = fList.CountItems(); 431 for (;count; count--) { 432 // workaround for BEntryList not having a proper destructor 433 BEntryList* entry = fList.RemoveItemAt(count - 1); 434 EntryListBase* fixedEntry = dynamic_cast<EntryListBase*>(entry); 435 436 if (fixedEntry) 437 delete fixedEntry; 438 else 439 delete entry; 440 } 441 } 442 443 444 void 445 EntryIteratorList::AddItem(BEntryList* walker) 446 { 447 fList.AddItem(walker); 448 } 449 450 451 status_t 452 EntryIteratorList::GetNextEntry(BEntry* entry, bool traverse) 453 { 454 while (true) { 455 if (fCurrentIndex >= fList.CountItems()) { 456 fStatus = B_ENTRY_NOT_FOUND; 457 break; 458 } 459 460 fStatus = fList.ItemAt(fCurrentIndex)->GetNextEntry(entry, traverse); 461 if (fStatus != B_ENTRY_NOT_FOUND) 462 break; 463 464 fCurrentIndex++; 465 } 466 return fStatus; 467 } 468 469 470 status_t 471 EntryIteratorList::GetNextRef(entry_ref* ref) 472 { 473 while (true) { 474 if (fCurrentIndex >= fList.CountItems()) { 475 fStatus = B_ENTRY_NOT_FOUND; 476 break; 477 } 478 479 fStatus = fList.ItemAt(fCurrentIndex)->GetNextRef(ref); 480 if (fStatus != B_ENTRY_NOT_FOUND) 481 break; 482 483 fCurrentIndex++; 484 } 485 return fStatus; 486 } 487 488 489 int32 490 EntryIteratorList::GetNextDirents(struct dirent* buffer, size_t length, 491 int32 count) 492 { 493 int32 result = 0; 494 while (true) { 495 if (fCurrentIndex >= fList.CountItems()) { 496 fStatus = B_ENTRY_NOT_FOUND; 497 break; 498 } 499 500 result = fList.ItemAt(fCurrentIndex)->GetNextDirents(buffer, length, 501 count); 502 if (result > 0) { 503 fStatus = B_OK; 504 break; 505 } 506 507 fCurrentIndex++; 508 } 509 return result; 510 } 511 512 513 status_t 514 EntryIteratorList::Rewind() 515 { 516 fCurrentIndex = 0; 517 int32 count = fList.CountItems(); 518 for (int32 index = 0; index < count; index++) 519 fStatus = fList.ItemAt(index)->Rewind(); 520 521 return fStatus; 522 } 523 524 525 int32 526 EntryIteratorList::CountEntries() 527 { 528 int32 result = 0; 529 530 int32 count = fList.CountItems(); 531 for (int32 index = 0; index < count; index++) 532 result += fList.ItemAt(fCurrentIndex)->CountEntries(); 533 534 return result; 535 } 536 537 538 // #pragma mark - 539 540 541 CachedEntryIteratorList::CachedEntryIteratorList(bool sortInodes) 542 : CachedEntryIterator(NULL, 10, sortInodes) 543 { 544 fStatus = B_OK; 545 SetTo(&fIteratorList); 546 } 547 548 549 void 550 CachedEntryIteratorList::AddItem(BEntryList* walker) 551 { 552 fIteratorList.AddItem(walker); 553 } 554