1/* 2Open Tracker License 3 4Terms and Conditions 5 6Copyright (c) 1991-2000, Be Incorporated. All rights reserved. 7 8Permission is hereby granted, free of charge, to any person obtaining a copy of 9this software and associated documentation files (the "Software"), to deal in 10the Software without restriction, including without limitation the rights to 11use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 12of the Software, and to permit persons to whom the Software is furnished to do 13so, subject to the following conditions: 14 15The above copyright notice and this permission notice applies to all licensees 16and shall be included in all copies or substantial portions of the Software. 17 18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY, 20FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 22AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION 23WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 25Except as contained in this notice, the name of Be Incorporated shall not be 26used in advertising or otherwise to promote the sale, use or other dealings in 27this Software without prior written authorization from Be Incorporated. 28 29Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks 30of Be Incorporated in the United States and other countries. Other brand product 31names are registered trademarks or trademarks of their respective holders. 32All 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 47TWalkerWrapper::TWalkerWrapper(BTrackerPrivate::TWalker* walker) 48 : 49 fWalker(walker), 50 fStatus(B_OK) 51{ 52} 53 54 55TWalkerWrapper::~TWalkerWrapper() 56{ 57 delete fWalker; 58} 59 60 61status_t 62TWalkerWrapper::InitCheck() const 63{ 64 return fStatus; 65} 66 67 68status_t 69TWalkerWrapper::GetNextEntry(BEntry* entry, bool traverse) 70{ 71 fStatus = fWalker->GetNextEntry(entry, traverse); 72 return fStatus; 73} 74 75 76status_t 77TWalkerWrapper::GetNextRef(entry_ref* ref) 78{ 79 fStatus = fWalker->GetNextRef(ref); 80 return fStatus; 81} 82 83 84int32 85TWalkerWrapper::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 94status_t 95TWalkerWrapper::Rewind() 96{ 97 return fWalker->Rewind(); 98} 99 100 101int32 102TWalkerWrapper::CountEntries() 103{ 104 return fWalker->CountEntries(); 105} 106 107 108// #pragma mark - 109 110 111EntryListBase::EntryListBase() 112 : fStatus(B_OK) 113{ 114} 115 116 117status_t 118EntryListBase::InitCheck() const 119{ 120 return fStatus; 121} 122 123 124dirent* 125EntryListBase::Next(dirent* ent) 126{ 127 return (dirent*)((char*)ent + ent->d_reclen); 128} 129 130 131// #pragma mark - 132 133 134CachedEntryIterator::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 151CachedEntryIterator::~CachedEntryIterator() 152{ 153 delete [] fEntryRefBuffer; 154 free(fDirentBuffer); 155 delete fSortedList; 156 delete [] fEntryBuffer; 157} 158 159 160status_t 161CachedEntryIterator::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 193status_t 194CachedEntryIterator::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 226CachedEntryIterator::_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 237int32 238CachedEntryIterator::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 317status_t 318CachedEntryIterator::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 332int32 333CachedEntryIterator::CountEntries() 334{ 335 return fIterator->CountEntries(); 336} 337 338 339void 340CachedEntryIterator::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 352CachedDirectoryEntryList::CachedDirectoryEntryList(const BDirectory &dir) 353 : CachedEntryIterator(0, 40, true), 354 fDir(dir) 355{ 356 fStatus = fDir.InitCheck(); 357 SetTo(&fDir); 358} 359 360 361CachedDirectoryEntryList::~CachedDirectoryEntryList() 362{ 363} 364 365 366// #pragma mark - 367 368 369DirectoryEntryList::DirectoryEntryList(const BDirectory &dir) 370 : 371 fDir(dir) 372{ 373 fStatus = fDir.InitCheck(); 374} 375 376 377status_t 378DirectoryEntryList::GetNextEntry(BEntry* entry, bool traverse) 379{ 380 fStatus = fDir.GetNextEntry(entry, traverse); 381 return fStatus; 382} 383 384 385status_t 386DirectoryEntryList::GetNextRef(entry_ref* ref) 387{ 388 fStatus = fDir.GetNextRef(ref); 389 return fStatus; 390} 391 392 393int32 394DirectoryEntryList::GetNextDirents(struct dirent* buffer, size_t length, 395 int32 count) 396{ 397 fStatus = fDir.GetNextDirents(buffer, length, count); 398 return fStatus; 399} 400 401 402status_t 403DirectoryEntryList::Rewind() 404{ 405 fStatus = fDir.Rewind(); 406 return fStatus; 407} 408 409 410int32 411DirectoryEntryList::CountEntries() 412{ 413 return fDir.CountEntries(); 414} 415 416 417// #pragma mark - 418 419 420EntryIteratorList::EntryIteratorList() 421 : 422 fList(5, true), 423 fCurrentIndex(0) 424{ 425} 426 427 428EntryIteratorList::~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 444void 445EntryIteratorList::AddItem(BEntryList* walker) 446{ 447 fList.AddItem(walker); 448} 449 450 451status_t 452EntryIteratorList::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 470status_t 471EntryIteratorList::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 489int32 490EntryIteratorList::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 513status_t 514EntryIteratorList::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 525int32 526EntryIteratorList::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 541CachedEntryIteratorList::CachedEntryIteratorList(bool sortInodes) 542 : CachedEntryIterator(NULL, 10, sortInodes) 543{ 544 fStatus = B_OK; 545 SetTo(&fIteratorList); 546} 547 548 549void 550CachedEntryIteratorList::AddItem(BEntryList* walker) 551{ 552 fIteratorList.AddItem(walker); 553} 554