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, int32 numEntries, 135 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 < (sizeof(dirent) + B_FILE_NAME_LENGTH)) { 269 // cant fit a big entryRef in the buffer, just bail 270 // and start from scratch 271 break; 272 } 273 274 fCurrentDirent 275 = (dirent *)((char *)fCurrentDirent + currentDirentSize); 276 } 277 fCurrentDirent = fDirentBuffer; 278 if (fSortInodes) { 279 if (!fSortedList) 280 fSortedList = new BObjectList<dirent>(fCacheSize); 281 else 282 fSortedList->MakeEmpty(); 283 284 for (int32 count = 0; count < fNumEntries; count++) { 285 fSortedList->AddItem(fCurrentDirent, 0); 286 fCurrentDirent = Next(fCurrentDirent); 287 } 288 fSortedList->SortItems(&_CompareInodes); 289 fCurrentDirent = fDirentBuffer; 290 } 291 fIndex = 0; 292 } 293 if (fIndex >= fNumEntries) { 294 // we are done, no more dirents left 295 return 0; 296 } 297 298 if (fSortInodes) 299 fCurrentDirent = fSortedList->ItemAt(fIndex); 300 301 fIndex++; 302 uint32 currentDirentSize = fCurrentDirent->d_reclen; 303 ASSERT(currentDirentSize <= size); 304 if (currentDirentSize > size) 305 return 0; 306 307 memcpy(ent, fCurrentDirent, currentDirentSize); 308 309 if (!fSortInodes) 310 fCurrentDirent = (dirent *)((char *)fCurrentDirent + currentDirentSize); 311 312 return 1; 313 } 314 315 316 status_t 317 CachedEntryIterator::Rewind() 318 { 319 fIndex = 0; 320 fNumEntries = 0; 321 fCurrentDirent = NULL; 322 fStatus = B_OK; 323 324 delete fSortedList; 325 fSortedList = NULL; 326 327 return fIterator->Rewind(); 328 } 329 330 331 int32 332 CachedEntryIterator::CountEntries() 333 { 334 return fIterator->CountEntries(); 335 } 336 337 338 void 339 CachedEntryIterator::SetTo(BEntryList *iterator) 340 { 341 fIndex = 0; 342 fNumEntries = 0; 343 fStatus = B_OK; 344 fIterator = iterator; 345 } 346 347 348 // #pragma mark - 349 350 351 CachedDirectoryEntryList::CachedDirectoryEntryList(const BDirectory &dir) 352 : CachedEntryIterator(0, 40, true), 353 fDir(dir) 354 { 355 fStatus = fDir.InitCheck(); 356 SetTo(&fDir); 357 } 358 359 360 CachedDirectoryEntryList::~CachedDirectoryEntryList() 361 { 362 } 363 364 365 // #pragma mark - 366 367 368 DirectoryEntryList::DirectoryEntryList(const BDirectory &dir) 369 : 370 fDir(dir) 371 { 372 fStatus = fDir.InitCheck(); 373 } 374 375 376 status_t 377 DirectoryEntryList::GetNextEntry(BEntry *entry, bool traverse) 378 { 379 fStatus = fDir.GetNextEntry(entry, traverse); 380 return fStatus; 381 } 382 383 384 status_t 385 DirectoryEntryList::GetNextRef(entry_ref *ref) 386 { 387 fStatus = fDir.GetNextRef(ref); 388 return fStatus; 389 } 390 391 392 int32 393 DirectoryEntryList::GetNextDirents(struct dirent *buffer, size_t length, 394 int32 count) 395 { 396 fStatus = fDir.GetNextDirents(buffer, length, count); 397 return fStatus; 398 } 399 400 401 status_t 402 DirectoryEntryList::Rewind() 403 { 404 fStatus = fDir.Rewind(); 405 return fStatus; 406 } 407 408 409 int32 410 DirectoryEntryList::CountEntries() 411 { 412 return fDir.CountEntries(); 413 } 414 415 416 // #pragma mark - 417 418 419 EntryIteratorList::EntryIteratorList() 420 : 421 fList(5, true), 422 fCurrentIndex(0) 423 { 424 } 425 426 427 EntryIteratorList::~EntryIteratorList() 428 { 429 int32 count = fList.CountItems(); 430 for (;count; count--) { 431 // workaround for BEntryList not having a proper destructor 432 BEntryList *entry = fList.RemoveItemAt(count - 1); 433 EntryListBase *fixedEntry = dynamic_cast<EntryListBase *>(entry); 434 435 if (fixedEntry) 436 delete fixedEntry; 437 else 438 delete entry; 439 } 440 } 441 442 443 void 444 EntryIteratorList::AddItem(BEntryList *walker) 445 { 446 fList.AddItem(walker); 447 } 448 449 450 status_t 451 EntryIteratorList::GetNextEntry(BEntry *entry, bool traverse) 452 { 453 while (true) { 454 if (fCurrentIndex >= fList.CountItems()) { 455 fStatus = B_ENTRY_NOT_FOUND; 456 break; 457 } 458 459 fStatus = fList.ItemAt(fCurrentIndex)->GetNextEntry(entry, traverse); 460 if (fStatus != B_ENTRY_NOT_FOUND) 461 break; 462 463 fCurrentIndex++; 464 } 465 return fStatus; 466 } 467 468 469 status_t 470 EntryIteratorList::GetNextRef(entry_ref *ref) 471 { 472 while (true) { 473 if (fCurrentIndex >= fList.CountItems()) { 474 fStatus = B_ENTRY_NOT_FOUND; 475 break; 476 } 477 478 fStatus = fList.ItemAt(fCurrentIndex)->GetNextRef(ref); 479 if (fStatus != B_ENTRY_NOT_FOUND) 480 break; 481 482 fCurrentIndex++; 483 } 484 return fStatus; 485 } 486 487 488 int32 489 EntryIteratorList::GetNextDirents(struct dirent *buffer, size_t length, 490 int32 count) 491 { 492 int32 result = 0; 493 while (true) { 494 if (fCurrentIndex >= fList.CountItems()) { 495 fStatus = B_ENTRY_NOT_FOUND; 496 break; 497 } 498 499 result = fList.ItemAt(fCurrentIndex)->GetNextDirents(buffer, length, 500 count); 501 if (result > 0) { 502 fStatus = B_OK; 503 break; 504 } 505 506 fCurrentIndex++; 507 } 508 return result; 509 } 510 511 512 status_t 513 EntryIteratorList::Rewind() 514 { 515 fCurrentIndex = 0; 516 int32 count = fList.CountItems(); 517 for (int32 index = 0; index < count; index++) 518 fStatus = fList.ItemAt(index)->Rewind(); 519 520 return fStatus; 521 } 522 523 524 int32 525 EntryIteratorList::CountEntries() 526 { 527 int32 result = 0; 528 529 int32 count = fList.CountItems(); 530 for (int32 index = 0; index < count; index++) 531 result += fList.ItemAt(fCurrentIndex)->CountEntries(); 532 533 return result; 534 } 535 536 537 // #pragma mark - 538 539 540 CachedEntryIteratorList::CachedEntryIteratorList(bool sortInodes) 541 : CachedEntryIterator(NULL, 10, sortInodes) 542 { 543 fStatus = B_OK; 544 SetTo(&fIteratorList); 545 } 546 547 548 void 549 CachedEntryIteratorList::AddItem(BEntryList *walker) 550 { 551 fIteratorList.AddItem(walker); 552 } 553 554