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