6 Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
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:
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.
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.
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.
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.
40 #include <SupportDefs.h>
42 #include "NodeWalker.h"
45 namespace BTrackerPrivate
{
52 // all the following calls are pure virtuals, should not get called
54 TWalker::GetNextEntry(BEntry
*, bool )
62 TWalker::GetNextRef(entry_ref
*)
70 TWalker::GetNextDirents(struct dirent
*, size_t, int32
)
86 TWalker::CountEntries()
93 TNodeWalker::TNodeWalker(bool includeTopDirectory
)
98 fIncludeTopDir(includeTopDirectory
),
99 fOriginalIncludeTopDir(includeTopDirectory
),
101 fOriginalJustFile(NULL
)
106 TNodeWalker::TNodeWalker(const char* path
, bool includeTopDirectory
)
111 fIncludeTopDir(includeTopDirectory
),
112 fOriginalIncludeTopDir(includeTopDirectory
),
114 fOriginalDirCopy(path
),
115 fOriginalJustFile(NULL
)
117 if (fOriginalDirCopy
.InitCheck() != B_OK
) {
118 // not a directory, set up walking a single file
119 fJustFile
= new BEntry(path
);
120 if (fJustFile
->InitCheck() != B_OK
) {
124 fOriginalJustFile
= fJustFile
;
126 fTopDir
= new BDirectory(fOriginalDirCopy
);
128 fDirs
.AddItem(fTopDir
);
133 TNodeWalker::TNodeWalker(const entry_ref
* ref
, bool includeTopDirectory
)
138 fIncludeTopDir(includeTopDirectory
),
139 fOriginalIncludeTopDir(includeTopDirectory
),
141 fOriginalDirCopy(ref
),
142 fOriginalJustFile(NULL
)
144 if (fOriginalDirCopy
.InitCheck() != B_OK
) {
145 // not a directory, set up walking a single file
146 fJustFile
= new BEntry(ref
);
147 if (fJustFile
->InitCheck() != B_OK
) {
151 fOriginalJustFile
= fJustFile
;
153 fTopDir
= new BDirectory(fOriginalDirCopy
);
155 fDirs
.AddItem(fTopDir
);
160 TNodeWalker::TNodeWalker(const BDirectory
* dir
, bool includeTopDirectory
)
165 fIncludeTopDir(includeTopDirectory
),
166 fOriginalIncludeTopDir(includeTopDirectory
),
168 fOriginalDirCopy(*dir
),
169 fOriginalJustFile(NULL
)
171 fTopDir
= new BDirectory(*dir
);
173 fDirs
.AddItem(fTopDir
);
177 TNodeWalker::TNodeWalker()
182 fIncludeTopDir(false),
183 fOriginalIncludeTopDir(false),
185 fOriginalJustFile(NULL
)
190 TNodeWalker::TNodeWalker(const char* path
)
195 fIncludeTopDir(false),
196 fOriginalIncludeTopDir(false),
198 fOriginalDirCopy(path
),
199 fOriginalJustFile(NULL
)
201 if (fOriginalDirCopy
.InitCheck() != B_OK
) {
202 // not a directory, set up walking a single file
203 fJustFile
= new BEntry(path
);
204 if (fJustFile
->InitCheck() != B_OK
) {
208 fOriginalJustFile
= fJustFile
;
210 fTopDir
= new BDirectory(fOriginalDirCopy
);
212 fDirs
.AddItem(fTopDir
);
217 TNodeWalker::TNodeWalker(const entry_ref
* ref
)
222 fIncludeTopDir(false),
223 fOriginalIncludeTopDir(false),
225 fOriginalDirCopy(ref
),
226 fOriginalJustFile(NULL
)
228 if (fOriginalDirCopy
.InitCheck() != B_OK
) {
229 // not a directory, set up walking a single file
230 fJustFile
= new BEntry(ref
);
231 if (fJustFile
->InitCheck() != B_OK
) {
235 fOriginalJustFile
= fJustFile
;
237 fTopDir
= new BDirectory(fOriginalDirCopy
);
239 fDirs
.AddItem(fTopDir
);
243 TNodeWalker::TNodeWalker(const BDirectory
* dir
)
248 fIncludeTopDir(false),
249 fOriginalIncludeTopDir(false),
251 fOriginalDirCopy(*dir
),
252 fOriginalJustFile(NULL
)
254 fTopDir
= new BDirectory(*dir
);
256 fDirs
.AddItem(fTopDir
);
260 TNodeWalker::~TNodeWalker()
262 delete fOriginalJustFile
;
265 BDirectory
* directory
= fDirs
.RemoveItemAt(fTopIndex
--);
266 if (directory
== NULL
)
275 TNodeWalker::PopDirCommon()
277 ASSERT(fTopIndex
>= 0);
279 // done with the old dir, pop it
280 fDirs
.RemoveItemAt(fTopIndex
);
285 if (fTopIndex
== -1) {
287 return B_ENTRY_NOT_FOUND
;
290 // point to the new top dir
291 fTopDir
= fDirs
.ItemAt(fTopIndex
);
298 TNodeWalker::PushDirCommon(const entry_ref
* ref
)
300 fTopDir
= new BDirectory(ref
);
301 // OK to ignore error here. Will
302 // catch at next call to GetNextEntry
304 fDirs
.AddItem(fTopDir
);
309 TNodeWalker::GetNextEntry(BEntry
* entry
, bool traverse
)
311 if (fJustFile
!= NULL
) {
317 if (fTopDir
== NULL
) {
319 return B_ENTRY_NOT_FOUND
;
322 // If requested to include the top directory, return that first.
323 if (fIncludeTopDir
) {
324 fIncludeTopDir
= false;
325 return fTopDir
->GetEntry(entry
);
328 // Get the next entry.
329 status_t result
= fTopDir
->GetNextEntry(entry
, traverse
);
330 if (result
!= B_OK
) {
331 result
= PopDirCommon();
335 return GetNextEntry(entry
, traverse
);
337 // See if this entry is a directory. If it is then push it onto the
340 result
= entry
->GetRef(&ref
);
342 if (result
== B_OK
&& fTopDir
->Contains(ref
.name
, B_DIRECTORY_NODE
))
350 TNodeWalker::GetNextRef(entry_ref
* ref
)
352 if (fJustFile
!= NULL
) {
353 fJustFile
->GetRef(ref
);
358 if (fTopDir
== NULL
) {
360 return B_ENTRY_NOT_FOUND
;
363 // If requested to include the top directory, return that first.
364 if (fIncludeTopDir
) {
365 fIncludeTopDir
= false;
367 status_t err
= fTopDir
->GetEntry(&entry
);
369 err
= entry
.GetRef(ref
);
373 // get the next entry
374 status_t err
= fTopDir
->GetNextRef(ref
);
376 err
= PopDirCommon();
379 return GetNextRef(ref
);
382 // See if this entry is a directory, if it is then push it onto the stack.
383 if (fTopDir
->Contains(ref
->name
, B_DIRECTORY_NODE
))
391 build_dirent(const BEntry
* source
, struct dirent
* ent
,
392 size_t size
, int32 count
)
395 source
->GetRef(&ref
);
397 size_t recordLength
= strlen(ref
.name
) + sizeof(dirent
);
398 if (recordLength
> size
|| count
<= 0) {
399 // can't fit in buffer, bail
403 // info about this node
404 ent
->d_reclen
= static_cast<ushort
>(recordLength
);
405 strcpy(ent
->d_name
, ref
.name
);
406 ent
->d_dev
= ref
.device
;
407 ent
->d_ino
= ref
.directory
;
409 // info about the parent
411 source
->GetParent(&parent
);
412 if (parent
.InitCheck() == B_OK
) {
414 parent
.GetRef(&parentRef
);
415 ent
->d_pdev
= parentRef
.device
;
416 ent
->d_pino
= parentRef
.directory
;
427 TNodeWalker::GetNextDirents(struct dirent
* ent
, size_t size
, int32 count
)
429 if (fJustFile
!= NULL
) {
433 // simulate GetNextDirents by building a single dirent structure
434 int32 result
= build_dirent(fJustFile
, ent
, size
, count
);
439 if (fTopDir
== NULL
) {
444 // If requested to include the top directory, return that first.
445 if (fIncludeTopDir
) {
446 fIncludeTopDir
= false;
448 if (fTopDir
->GetEntry(&entry
) < B_OK
)
451 return build_dirent(fJustFile
, ent
, size
, count
);
454 // get the next entry
455 int32 nextDirent
= fTopDir
->GetNextDirents(ent
, size
, count
);
456 if (nextDirent
== 0) {
457 status_t result
= PopDirCommon();
461 return GetNextDirents(ent
, size
, count
);
464 // push any directories in the returned entries onto the stack
465 for (int32 i
= 0; i
< nextDirent
; i
++) {
466 if (fTopDir
->Contains(ent
->d_name
, B_DIRECTORY_NODE
)) {
467 entry_ref
ref(ent
->d_dev
, ent
->d_ino
, ent
->d_name
);
470 ent
= (dirent
*)((char*)ent
+ ent
->d_reclen
);
478 TNodeWalker::Rewind()
480 if (fOriginalJustFile
!= NULL
) {
481 // single file mode, rewind by pointing to the original file
482 fJustFile
= fOriginalJustFile
;
486 // pop all the directories and point to the initial one
488 BDirectory
* directory
= fDirs
.RemoveItemAt(fTopIndex
--);
489 if (directory
== NULL
)
495 fTopDir
= new BDirectory(fOriginalDirCopy
);
497 fIncludeTopDir
= fOriginalIncludeTopDir
;
498 fDirs
.AddItem(fTopDir
);
500 return fTopDir
->Rewind();
501 // rewind the directory
505 TNodeWalker::CountEntries()
507 // should not be calling this
513 TVolWalker::TVolWalker(bool knowsAttributes
, bool writable
,
514 bool includeTopDirectory
)
516 TNodeWalker(includeTopDirectory
),
517 fKnowsAttr(knowsAttributes
),
520 // Get things initialized. Find first volume, or find the first volume
521 // that supports attributes.
526 TVolWalker::~TVolWalker()
532 TVolWalker::NextVolume()
534 // The stack of directoies should be empty.
535 ASSERT(fTopIndex
== -1);
536 ASSERT(fTopDir
== NULL
);
540 result
= fVolRoster
.GetNextVolume(&fVol
);
543 } while ((fKnowsAttr
&& !fVol
.KnowsAttr())
544 || (fWritable
&& fVol
.IsReadOnly()));
546 if (result
== B_OK
) {
547 // Get the root directory to get things started. There's always
548 // a root directory for a volume. So if there is an error then it
549 // means that something is really bad, like the system is out of
550 // memory. In that case don't worry about truying to skip to the
552 fTopDir
= new BDirectory();
553 result
= fVol
.GetRootDirectory(fTopDir
);
554 fIncludeTopDir
= fOriginalIncludeTopDir
;
556 fDirs
.AddItem(fTopDir
);
563 TVolWalker::GetNextEntry(BEntry
* entry
, bool traverse
)
566 return B_ENTRY_NOT_FOUND
;
568 // get the next entry
569 status_t result
= _inherited::GetNextEntry(entry
, traverse
);
570 while (result
!= B_OK
) {
571 // we're done with the current volume, go to the next one
572 result
= NextVolume();
576 result
= GetNextEntry(entry
, traverse
);
584 TVolWalker::GetNextRef(entry_ref
* ref
)
587 return B_ENTRY_NOT_FOUND
;
590 status_t result
= _inherited::GetNextRef(ref
);
592 while (result
!= B_OK
) {
593 // we're done with the current volume, go to the next one
594 result
= NextVolume();
597 result
= GetNextRef(ref
);
605 TVolWalker::GetNextDirents(struct dirent
* ent
, size_t size
, int32 count
)
608 return B_ENTRY_NOT_FOUND
;
610 // get the next dirent
611 status_t result
= _inherited::GetNextDirents(ent
, size
, count
);
612 while (result
!= B_OK
) {
613 // we're done with the current volume, go to the next one
614 result
= NextVolume();
618 result
= GetNextDirents(ent
, size
, count
);
633 TQueryWalker::TQueryWalker(const char* predicate
)
638 fPredicate
= strdup(predicate
);
643 TQueryWalker::~TQueryWalker()
645 free((char*)fPredicate
);
651 TQueryWalker::GetNextEntry(BEntry
* entry
, bool traverse
)
655 result
= fQuery
.GetNextEntry(entry
, traverse
);
656 if (result
== B_ENTRY_NOT_FOUND
) {
657 if (NextVolume() != B_OK
)
660 } while (result
== B_ENTRY_NOT_FOUND
);
667 TQueryWalker::GetNextRef(entry_ref
* ref
)
672 result
= fQuery
.GetNextRef(ref
);
673 if (result
!= B_ENTRY_NOT_FOUND
)
676 result
= NextVolume();
686 TQueryWalker::GetNextDirents(struct dirent
* ent
, size_t size
, int32 count
)
691 result
= fQuery
.GetNextDirents(ent
, size
, count
);
695 if (NextVolume() != B_OK
)
704 TQueryWalker::NextVolume()
708 result
= fVolRoster
.GetNextVolume(&fVol
);
711 } while (!fVol
.KnowsQuery());
713 if (result
== B_OK
) {
714 result
= fQuery
.Clear();
715 result
= fQuery
.SetVolume(&fVol
);
716 result
= fQuery
.SetPredicate(fPredicate
);
717 result
= fQuery
.Fetch();
725 TQueryWalker::CountEntries()
727 // should not be calling this
734 TQueryWalker::Rewind()
740 } // namespace BTrackerPrivate