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