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 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 50TWalkerWrapper::TWalkerWrapper(BTrackerPrivate::TWalker* walker) 51 : 52 fWalker(walker), 53 fStatus(B_OK) 54{ 55} 56 57 58TWalkerWrapper::~TWalkerWrapper() 59{ 60 delete fWalker; 61} 62 63 64status_t 65TWalkerWrapper::InitCheck() const 66{ 67 return fStatus; 68} 69 70 71status_t 72TWalkerWrapper::GetNextEntry(BEntry* entry, bool traverse) 73{ 74 fStatus = fWalker->GetNextEntry(entry, traverse); 75 76 return fStatus; 77} 78 79 80status_t 81TWalkerWrapper::GetNextRef(entry_ref* ref) 82{ 83 fStatus = fWalker->GetNextRef(ref); 84 85 return fStatus; 86} 87 88 89int32 90TWalkerWrapper::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 100status_t 101TWalkerWrapper::Rewind() 102{ 103 return fWalker->Rewind(); 104} 105 106 107int32 108TWalkerWrapper::CountEntries() 109{ 110 return fWalker->CountEntries(); 111} 112 113 114// #pragma mark - EntryListBase 115 116 117EntryListBase::EntryListBase() 118 : 119 fStatus(B_OK) 120{ 121} 122 123 124status_t 125EntryListBase::InitCheck() const 126{ 127 return fStatus; 128} 129 130 131dirent* 132EntryListBase::Next(dirent* ent) 133{ 134 return (dirent*)((char*)ent + ent->d_reclen); 135} 136 137 138// #pragma mark - CachedEntryIterator 139 140 141CachedEntryIterator::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 158CachedEntryIterator::~CachedEntryIterator() 159{ 160 delete[] fEntryRefBuffer; 161 free(fDirentBuffer); 162 delete fSortedList; 163 delete[] fEntryBuffer; 164} 165 166 167status_t 168CachedEntryIterator::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 202status_t 203CachedEntryIterator::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 237CachedEntryIterator::_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 249int32 250CachedEntryIterator::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 329status_t 330CachedEntryIterator::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 344int32 345CachedEntryIterator::CountEntries() 346{ 347 return fIterator->CountEntries(); 348} 349 350 351void 352CachedEntryIterator::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 364CachedDirectoryEntryList::CachedDirectoryEntryList(const BDirectory& directory) 365 : 366 CachedEntryIterator(0, 40, true), 367 fDirectory(directory) 368{ 369 fStatus = fDirectory.InitCheck(); 370 SetTo(&fDirectory); 371} 372 373 374CachedDirectoryEntryList::~CachedDirectoryEntryList() 375{ 376} 377 378 379// #pragma mark - DirectoryEntryList 380 381 382DirectoryEntryList::DirectoryEntryList(const BDirectory& directory) 383 : 384 fDirectory(directory) 385{ 386 fStatus = fDirectory.InitCheck(); 387} 388 389 390status_t 391DirectoryEntryList::GetNextEntry(BEntry* entry, bool traverse) 392{ 393 fStatus = fDirectory.GetNextEntry(entry, traverse); 394 return fStatus; 395} 396 397 398status_t 399DirectoryEntryList::GetNextRef(entry_ref* ref) 400{ 401 fStatus = fDirectory.GetNextRef(ref); 402 return fStatus; 403} 404 405 406int32 407DirectoryEntryList::GetNextDirents(struct dirent* buffer, size_t length, 408 int32 count) 409{ 410 fStatus = fDirectory.GetNextDirents(buffer, length, count); 411 return fStatus; 412} 413 414 415status_t 416DirectoryEntryList::Rewind() 417{ 418 fStatus = fDirectory.Rewind(); 419 return fStatus; 420} 421 422 423int32 424DirectoryEntryList::CountEntries() 425{ 426 return fDirectory.CountEntries(); 427} 428 429 430// #pragma mark - EntryIteratorList 431 432 433EntryIteratorList::EntryIteratorList() 434 : 435 fList(5, true), 436 fCurrentIndex(0) 437{ 438} 439 440 441EntryIteratorList::~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 456void 457EntryIteratorList::AddItem(BEntryList* walker) 458{ 459 fList.AddItem(walker); 460} 461 462 463status_t 464EntryIteratorList::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 482status_t 483EntryIteratorList::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 501int32 502EntryIteratorList::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 525status_t 526EntryIteratorList::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 537int32 538EntryIteratorList::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 553CachedEntryIteratorList::CachedEntryIteratorList(bool sortInodes) 554 : 555 CachedEntryIterator(NULL, 10, sortInodes) 556{ 557 fStatus = B_OK; 558 SetTo(&fIteratorList); 559} 560 561 562void 563CachedEntryIteratorList::AddItem(BEntryList* walker) 564{ 565 fIteratorList.AddItem(walker); 566} 567