btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / kits / tracker / NodeWalker.cpp
blob87184b0f08edbd8386b9941a25cc0473a3b46748
1 /*
2 Open Tracker License
4 Terms and Conditions
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.
32 All rights reserved.
36 #include <Debug.h>
37 #include <stdio.h>
38 #include <string.h>
39 #include <errno.h>
40 #include <SupportDefs.h>
42 #include "NodeWalker.h"
45 namespace BTrackerPrivate {
47 TWalker::~TWalker()
52 // all the following calls are pure virtuals, should not get called
53 status_t
54 TWalker::GetNextEntry(BEntry*, bool )
56 TRESPASS();
57 return B_ERROR;
61 status_t
62 TWalker::GetNextRef(entry_ref*)
64 TRESPASS();
65 return B_ERROR;
69 int32
70 TWalker::GetNextDirents(struct dirent*, size_t, int32)
72 TRESPASS();
73 return 0;
77 status_t
78 TWalker::Rewind()
80 TRESPASS();
81 return B_ERROR;
85 int32
86 TWalker::CountEntries()
88 TRESPASS();
89 return -1;
93 TNodeWalker::TNodeWalker(bool includeTopDirectory)
95 fDirs(20),
96 fTopIndex(-1),
97 fTopDir(NULL),
98 fIncludeTopDir(includeTopDirectory),
99 fOriginalIncludeTopDir(includeTopDirectory),
100 fJustFile(NULL),
101 fOriginalJustFile(NULL)
106 TNodeWalker::TNodeWalker(const char* path, bool includeTopDirectory)
108 fDirs(20),
109 fTopIndex(-1),
110 fTopDir(NULL),
111 fIncludeTopDir(includeTopDirectory),
112 fOriginalIncludeTopDir(includeTopDirectory),
113 fJustFile(NULL),
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) {
121 delete fJustFile;
122 fJustFile = NULL;
124 fOriginalJustFile = fJustFile;
125 } else {
126 fTopDir = new BDirectory(fOriginalDirCopy);
127 fTopIndex++;
128 fDirs.AddItem(fTopDir);
133 TNodeWalker::TNodeWalker(const entry_ref* ref, bool includeTopDirectory)
135 fDirs(20),
136 fTopIndex(-1),
137 fTopDir(NULL),
138 fIncludeTopDir(includeTopDirectory),
139 fOriginalIncludeTopDir(includeTopDirectory),
140 fJustFile(NULL),
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) {
148 delete fJustFile;
149 fJustFile = NULL;
151 fOriginalJustFile = fJustFile;
152 } else {
153 fTopDir = new BDirectory(fOriginalDirCopy);
154 fTopIndex++;
155 fDirs.AddItem(fTopDir);
160 TNodeWalker::TNodeWalker(const BDirectory* dir, bool includeTopDirectory)
162 fDirs(20),
163 fTopIndex(-1),
164 fTopDir(NULL),
165 fIncludeTopDir(includeTopDirectory),
166 fOriginalIncludeTopDir(includeTopDirectory),
167 fJustFile(NULL),
168 fOriginalDirCopy(*dir),
169 fOriginalJustFile(NULL)
171 fTopDir = new BDirectory(*dir);
172 fTopIndex++;
173 fDirs.AddItem(fTopDir);
177 TNodeWalker::TNodeWalker()
179 fDirs(20),
180 fTopIndex(-1),
181 fTopDir(NULL),
182 fIncludeTopDir(false),
183 fOriginalIncludeTopDir(false),
184 fJustFile(NULL),
185 fOriginalJustFile(NULL)
190 TNodeWalker::TNodeWalker(const char* path)
192 fDirs(20),
193 fTopIndex(-1),
194 fTopDir(NULL),
195 fIncludeTopDir(false),
196 fOriginalIncludeTopDir(false),
197 fJustFile(NULL),
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) {
205 delete fJustFile;
206 fJustFile = NULL;
208 fOriginalJustFile = fJustFile;
209 } else {
210 fTopDir = new BDirectory(fOriginalDirCopy);
211 fTopIndex++;
212 fDirs.AddItem(fTopDir);
217 TNodeWalker::TNodeWalker(const entry_ref* ref)
219 fDirs(20),
220 fTopIndex(-1),
221 fTopDir(NULL),
222 fIncludeTopDir(false),
223 fOriginalIncludeTopDir(false),
224 fJustFile(NULL),
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) {
232 delete fJustFile;
233 fJustFile = NULL;
235 fOriginalJustFile = fJustFile;
236 } else {
237 fTopDir = new BDirectory(fOriginalDirCopy);
238 fTopIndex++;
239 fDirs.AddItem(fTopDir);
243 TNodeWalker::TNodeWalker(const BDirectory* dir)
245 fDirs(20),
246 fTopIndex(-1),
247 fTopDir(NULL),
248 fIncludeTopDir(false),
249 fOriginalIncludeTopDir(false),
250 fJustFile(NULL),
251 fOriginalDirCopy(*dir),
252 fOriginalJustFile(NULL)
254 fTopDir = new BDirectory(*dir);
255 fTopIndex++;
256 fDirs.AddItem(fTopDir);
260 TNodeWalker::~TNodeWalker()
262 delete fOriginalJustFile;
264 for (;;) {
265 BDirectory* directory = fDirs.RemoveItemAt(fTopIndex--);
266 if (directory == NULL)
267 break;
269 delete directory;
274 status_t
275 TNodeWalker::PopDirCommon()
277 ASSERT(fTopIndex >= 0);
279 // done with the old dir, pop it
280 fDirs.RemoveItemAt(fTopIndex);
281 fTopIndex--;
282 delete fTopDir;
283 fTopDir = NULL;
285 if (fTopIndex == -1) {
286 // done
287 return B_ENTRY_NOT_FOUND;
290 // point to the new top dir
291 fTopDir = fDirs.ItemAt(fTopIndex);
293 return B_OK;
297 void
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
303 fTopIndex++;
304 fDirs.AddItem(fTopDir);
308 status_t
309 TNodeWalker::GetNextEntry(BEntry* entry, bool traverse)
311 if (fJustFile != NULL) {
312 *entry = *fJustFile;
313 fJustFile = 0;
314 return B_OK;
317 if (fTopDir == NULL) {
318 // done
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();
332 if (result != B_OK)
333 return result;
335 return GetNextEntry(entry, traverse);
337 // See if this entry is a directory. If it is then push it onto the
338 // stack
339 entry_ref ref;
340 result = entry->GetRef(&ref);
342 if (result == B_OK && fTopDir->Contains(ref.name, B_DIRECTORY_NODE))
343 PushDirCommon(&ref);
345 return result;
349 status_t
350 TNodeWalker::GetNextRef(entry_ref* ref)
352 if (fJustFile != NULL) {
353 fJustFile->GetRef(ref);
354 fJustFile = 0;
355 return B_OK;
358 if (fTopDir == NULL) {
359 // done
360 return B_ENTRY_NOT_FOUND;
363 // If requested to include the top directory, return that first.
364 if (fIncludeTopDir) {
365 fIncludeTopDir = false;
366 BEntry entry;
367 status_t err = fTopDir->GetEntry(&entry);
368 if (err == B_OK)
369 err = entry.GetRef(ref);
370 return err;
373 // get the next entry
374 status_t err = fTopDir->GetNextRef(ref);
375 if (err != B_OK) {
376 err = PopDirCommon();
377 if (err != B_OK)
378 return err;
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))
384 PushDirCommon(ref);
386 return B_OK;
390 static int32
391 build_dirent(const BEntry* source, struct dirent* ent,
392 size_t size, int32 count)
394 entry_ref ref;
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
400 return 0;
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
410 BEntry parent;
411 source->GetParent(&parent);
412 if (parent.InitCheck() == B_OK) {
413 entry_ref parentRef;
414 parent.GetRef(&parentRef);
415 ent->d_pdev = parentRef.device;
416 ent->d_pino = parentRef.directory;
417 } else {
418 ent->d_pdev = 0;
419 ent->d_pino = 0;
422 return 1;
426 int32
427 TNodeWalker::GetNextDirents(struct dirent* ent, size_t size, int32 count)
429 if (fJustFile != NULL) {
430 if (count == 0)
431 return 0;
433 // simulate GetNextDirents by building a single dirent structure
434 int32 result = build_dirent(fJustFile, ent, size, count);
435 fJustFile = 0;
436 return result;
439 if (fTopDir == NULL) {
440 // done
441 return 0;
444 // If requested to include the top directory, return that first.
445 if (fIncludeTopDir) {
446 fIncludeTopDir = false;
447 BEntry entry;
448 if (fTopDir->GetEntry(&entry) < B_OK)
449 return 0;
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();
458 if (result != B_OK)
459 return 0;
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);
468 PushDirCommon(&ref);
470 ent = (dirent*)((char*)ent + ent->d_reclen);
473 return nextDirent;
477 status_t
478 TNodeWalker::Rewind()
480 if (fOriginalJustFile != NULL) {
481 // single file mode, rewind by pointing to the original file
482 fJustFile = fOriginalJustFile;
483 return B_OK;
486 // pop all the directories and point to the initial one
487 for (;;) {
488 BDirectory* directory = fDirs.RemoveItemAt(fTopIndex--);
489 if (directory == NULL)
490 break;
492 delete directory;
495 fTopDir = new BDirectory(fOriginalDirCopy);
496 fTopIndex = 0;
497 fIncludeTopDir = fOriginalIncludeTopDir;
498 fDirs.AddItem(fTopDir);
500 return fTopDir->Rewind();
501 // rewind the directory
504 int32
505 TNodeWalker::CountEntries()
507 // should not be calling this
508 TRESPASS();
509 return -1;
513 TVolWalker::TVolWalker(bool knowsAttributes, bool writable,
514 bool includeTopDirectory)
516 TNodeWalker(includeTopDirectory),
517 fKnowsAttr(knowsAttributes),
518 fWritable(writable)
520 // Get things initialized. Find first volume, or find the first volume
521 // that supports attributes.
522 NextVolume();
526 TVolWalker::~TVolWalker()
531 status_t
532 TVolWalker::NextVolume()
534 // The stack of directoies should be empty.
535 ASSERT(fTopIndex == -1);
536 ASSERT(fTopDir == NULL);
538 status_t result;
539 do {
540 result = fVolRoster.GetNextVolume(&fVol);
541 if (result != B_OK)
542 break;
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
551 // next volume.
552 fTopDir = new BDirectory();
553 result = fVol.GetRootDirectory(fTopDir);
554 fIncludeTopDir = fOriginalIncludeTopDir;
555 fTopIndex = 0;
556 fDirs.AddItem(fTopDir);
559 return result;
562 status_t
563 TVolWalker::GetNextEntry(BEntry* entry, bool traverse)
565 if (fTopDir == NULL)
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();
573 if (result != B_OK)
574 break;
576 result = GetNextEntry(entry, traverse);
579 return result;
583 status_t
584 TVolWalker::GetNextRef(entry_ref* ref)
586 if (fTopDir == NULL)
587 return B_ENTRY_NOT_FOUND;
589 // Get the next ref.
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();
595 if (result != B_OK)
596 break;
597 result = GetNextRef(ref);
600 return result;
604 int32
605 TVolWalker::GetNextDirents(struct dirent* ent, size_t size, int32 count)
607 if (fTopDir == NULL)
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();
615 if (result != B_OK)
616 break;
618 result = GetNextDirents(ent, size, count);
621 return result;
625 status_t
626 TVolWalker::Rewind()
628 fVolRoster.Rewind();
629 return NextVolume();
633 TQueryWalker::TQueryWalker(const char* predicate)
635 TWalker(),
636 fTime(0)
638 fPredicate = strdup(predicate);
639 NextVolume();
643 TQueryWalker::~TQueryWalker()
645 free((char*)fPredicate);
646 fPredicate = NULL;
650 status_t
651 TQueryWalker::GetNextEntry(BEntry* entry, bool traverse)
653 status_t result;
654 do {
655 result = fQuery.GetNextEntry(entry, traverse);
656 if (result == B_ENTRY_NOT_FOUND) {
657 if (NextVolume() != B_OK)
658 break;
660 } while (result == B_ENTRY_NOT_FOUND);
662 return result;
666 status_t
667 TQueryWalker::GetNextRef(entry_ref* ref)
669 status_t result;
671 for (;;) {
672 result = fQuery.GetNextRef(ref);
673 if (result != B_ENTRY_NOT_FOUND)
674 break;
676 result = NextVolume();
677 if (result != B_OK)
678 break;
681 return result;
685 int32
686 TQueryWalker::GetNextDirents(struct dirent* ent, size_t size, int32 count)
688 int32 result;
690 for (;;) {
691 result = fQuery.GetNextDirents(ent, size, count);
692 if (result != 0)
693 return result;
695 if (NextVolume() != B_OK)
696 return 0;
699 return result;
703 status_t
704 TQueryWalker::NextVolume()
706 status_t result;
707 do {
708 result = fVolRoster.GetNextVolume(&fVol);
709 if (result != B_OK)
710 break;
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();
720 return result;
724 int32
725 TQueryWalker::CountEntries()
727 // should not be calling this
728 TRESPASS();
729 return -1;
733 status_t
734 TQueryWalker::Rewind()
736 fVolRoster.Rewind();
737 return NextVolume();
740 } // namespace BTrackerPrivate