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