From 24b218c5a7f41f1ab470ef2daad18029061fe211 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Tue, 21 Sep 2010 20:42:13 +0000 Subject: [PATCH] * Implemented a class that can handle Tracker's query files. Only read support for now. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@38767 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/private/shared/QueryFile.h | 66 ++++++ src/kits/shared/Jamfile | 2 + src/kits/shared/QueryFile.cpp | 357 +++++++++++++++++++++++++++++ 3 files changed, 425 insertions(+) create mode 100644 headers/private/shared/QueryFile.h create mode 100644 src/kits/shared/QueryFile.cpp diff --git a/headers/private/shared/QueryFile.h b/headers/private/shared/QueryFile.h new file mode 100644 index 0000000000..5558e63fda --- /dev/null +++ b/headers/private/shared/QueryFile.h @@ -0,0 +1,66 @@ +/* + * Copyright 2010, Axel Dörfler, axeld@pinc-software.de. + * This file may be used under the terms of the MIT License. + */ +#ifndef _QUERY_FILE_H +#define _QUERY_FILE_H + + +#include +#include +#include +#include + + +class BQueryFile : public BEntryList { +public: + BQueryFile(const entry_ref& ref); + BQueryFile(const BEntry& entry); + BQueryFile(const char* path); + BQueryFile(BQuery& query); + virtual ~BQueryFile(); + + status_t InitCheck() const; + + status_t SetTo(const entry_ref& ref); + status_t SetTo(const BEntry& entry); + status_t SetTo(const char* path); + status_t SetTo(BQuery& query); + void Unset(); + + status_t SetPredicate(const char* predicate); + status_t AddVolume(const BVolume& volume); + status_t AddVolume(dev_t device); + + const char* Predicate() const; + int32 CountVolumes() const; + dev_t VolumeAt(int32 index) const; + + status_t WriteTo(const entry_ref& ref); + status_t WriteTo(const char* path); + + // BEntryList implementation + + virtual status_t GetNextEntry(BEntry* entry, + bool traverse = false); + virtual status_t GetNextRef(entry_ref* ref); + virtual int32 GetNextDirents(struct dirent* buffer, + size_t length, int32 count = INT_MAX); + virtual status_t Rewind(); + virtual int32 CountEntries(); + + static const char* MimeType(); + +private: + status_t _SetQuery(int32 index); + +private: + status_t fStatus; + BString fPredicate; + BQuery fQuery; + BList fVolumes; + int32 fCurrentVolumeIndex; +}; + + +#endif // _QUERY_FILE_H diff --git a/src/kits/shared/Jamfile b/src/kits/shared/Jamfile index fa8ead14e9..b7607654f4 100644 --- a/src/kits/shared/Jamfile +++ b/src/kits/shared/Jamfile @@ -6,6 +6,7 @@ AddSubDirSupportedPlatforms libbe_test ; UseLibraryHeaders agg ; UsePrivateHeaders shared libbe ; UseHeaders [ FDirName $(HAIKU_COMMON_DEBUG_OBJECT_DIR) servers input ] ; +UseHeaders [ FDirName $(HAIKU_TOP) src kits ] ; # for RWLockManager only UsePrivateSystemHeaders ; @@ -19,6 +20,7 @@ StaticLibrary libshared.a : DragTrackingFilter.cpp HashString.cpp Keymap.cpp + QueryFile.cpp RWLockManager.cpp SHA256.cpp ShakeTrackingFilter.cpp diff --git a/src/kits/shared/QueryFile.cpp b/src/kits/shared/QueryFile.cpp new file mode 100644 index 0000000000..05314be9bb --- /dev/null +++ b/src/kits/shared/QueryFile.cpp @@ -0,0 +1,357 @@ +/* + * Copyright 2010, Axel Dörfler, axeld@pinc-software.de. + * This file may be used under the terms of the MIT License. + */ + + +#include + +#include +#include +#include + +#include "tracker/MimeTypes.h" +#include "tracker/Utilities.h" + + +// TODO: add write support +// TODO: let Tracker use it? +// TODO: live query support? + + +const char* kAttrQueryString = "_trk/qrystr"; +const char* kAttrQueryVolume = "_trk/qryvol1"; + + +BQueryFile::BQueryFile(const entry_ref& ref) +{ + SetTo(ref); +} + + +BQueryFile::BQueryFile(const BEntry& entry) +{ + SetTo(entry); +} + + +BQueryFile::BQueryFile(const char* path) +{ + SetTo(path); +} + + +BQueryFile::BQueryFile(BQuery& query) +{ + SetTo(query); +} + + +BQueryFile::~BQueryFile() +{ +} + + +status_t +BQueryFile::InitCheck() const +{ + return fStatus; +} + + +status_t +BQueryFile::SetTo(const entry_ref& ref) +{ + Unset(); + + BNode node(&ref); + fStatus = node.InitCheck(); + if (fStatus != B_OK) + return fStatus; + + ssize_t bytesRead = node.ReadAttrString(kAttrQueryString, &fPredicate); + if (bytesRead < 0) + return fStatus = bytesRead; + + bool searchAllVolumes = true; + attr_info info; + if (node.GetAttrInfo(kAttrQueryVolume, &info) == B_OK) { + void* buffer = malloc(info.size); + if (buffer == NULL) + return fStatus = B_NO_MEMORY; + + BMessage message; + fStatus = message.Unflatten((const char*)buffer); + if (fStatus == B_OK) { + for (int32 index = 0; index < 100; index++) { + BVolume volume; + status_t status = BPrivate::MatchArchivedVolume(&volume, + &message, index); + if (status == B_OK) { + fStatus = AddVolume(volume); + if (fStatus != B_OK) + break; + + searchAllVolumes = false; + } else if (status != B_DEV_BAD_DRIVE_NUM) { + // Volume doesn't seem to be mounted + fStatus = status; + break; + } + } + } + + free(buffer); + } + + if (searchAllVolumes) { + // add all volumes to query + BVolumeRoster roster; + BVolume volume; + while (roster.GetNextVolume(&volume) == B_OK) { + if (volume.IsPersistent() && volume.KnowsQuery()) + AddVolume(volume); + } + } + + return fStatus; +} + + +status_t +BQueryFile::SetTo(const BEntry& entry) +{ + entry_ref ref; + fStatus = entry.GetRef(&ref); + if (fStatus != B_OK) + return fStatus; + + return SetTo(ref); +} + + +status_t +BQueryFile::SetTo(const char* path) +{ + entry_ref ref; + fStatus = get_ref_for_path(path, &ref); + if (fStatus != B_OK) + return fStatus; + + return SetTo(ref); +} + + +status_t +BQueryFile::SetTo(BQuery& query) +{ + Unset(); + + BString predicate; + query.GetPredicate(&predicate); + + fStatus = SetPredicate(predicate.String()); + if (fStatus != B_OK) + return fStatus; + + return fStatus = AddVolume(query.TargetDevice()); +} + + +void +BQueryFile::Unset() +{ + fStatus = B_NO_INIT; + fCurrentVolumeIndex = -1; + fVolumes.MakeEmpty(); + fQuery.Clear(); + fPredicate = ""; +} + + +status_t +BQueryFile::SetPredicate(const char* predicate) +{ + fPredicate = predicate; + return B_OK; +} + + +status_t +BQueryFile::AddVolume(const BVolume& volume) +{ + return fVolumes.AddItem((void*)volume.Device()) ? B_OK : B_NO_MEMORY; +} + + +status_t +BQueryFile::AddVolume(dev_t device) +{ + return fVolumes.AddItem((void*)device) ? B_OK : B_NO_MEMORY; +} + + +const char* +BQueryFile::Predicate() const +{ + return fPredicate.String(); +} + + +int32 +BQueryFile::CountVolumes() const +{ + return fVolumes.CountItems(); +} + + +dev_t +BQueryFile::VolumeAt(int32 index) const +{ + if (index < 0 || index >= fVolumes.CountItems()) + return -1; + + return (dev_t)fVolumes.ItemAt(index); +} + + +status_t +BQueryFile::WriteTo(const entry_ref& ref) +{ + // TODO: implement + return B_NOT_SUPPORTED; +} + + +status_t +BQueryFile::WriteTo(const char* path) +{ + entry_ref ref; + status_t status = get_ref_for_path(path, &ref); + if (status != B_OK) + return status; + + return WriteTo(ref); +} + + +// #pragma mark - BEntryList implementation + + +status_t +BQueryFile::GetNextEntry(BEntry* entry, bool traverse) +{ + if (fCurrentVolumeIndex == -1) { + // Start with first volume + fCurrentVolumeIndex = 0; + + status_t status = _SetQuery(0); + if (status != B_OK) + return status; + } + + status_t status = B_ENTRY_NOT_FOUND; + + while (fCurrentVolumeIndex < CountVolumes()) { + status = fQuery.GetNextEntry(entry, traverse); + if (status != B_ENTRY_NOT_FOUND) + break; + + // Continue with next volume, if any + status = _SetQuery(++fCurrentVolumeIndex); + } + + return status; +} + + +status_t +BQueryFile::GetNextRef(entry_ref* ref) +{ + if (fCurrentVolumeIndex == -1) { + // Start with first volume + fCurrentVolumeIndex = 0; + + status_t status = _SetQuery(0); + if (status != B_OK) + return status; + } + + status_t status = B_ENTRY_NOT_FOUND; + + while (fCurrentVolumeIndex < CountVolumes()) { + status = fQuery.GetNextRef(ref); + if (status != B_ENTRY_NOT_FOUND) + break; + + // Continue with next volume, if any + status = _SetQuery(++fCurrentVolumeIndex); + } + + return status; +} + + +int32 +BQueryFile::GetNextDirents(struct dirent* buffer, size_t length, int32 count) +{ + if (fCurrentVolumeIndex == -1) { + // Start with first volume + fCurrentVolumeIndex = 0; + + status_t status = _SetQuery(0); + if (status != B_OK) + return status; + } + + status_t status = B_ENTRY_NOT_FOUND; + + while (fCurrentVolumeIndex < CountVolumes()) { + status = fQuery.GetNextDirents(buffer, length, count); + if (status != B_ENTRY_NOT_FOUND) + break; + + // Continue with next volume, if any + status = _SetQuery(++fCurrentVolumeIndex); + } + + return status; +} + + +status_t +BQueryFile::Rewind() +{ + fCurrentVolumeIndex = -1; + return B_OK; +} + + +int32 +BQueryFile::CountEntries() +{ + // not supported + return -1; +} + + +/*static*/ const char* +BQueryFile::MimeType() +{ + return B_QUERY_MIMETYPE; +} + + +status_t +BQueryFile::_SetQuery(int32 index) +{ + if (fCurrentVolumeIndex >= CountVolumes()) + return B_ENTRY_NOT_FOUND; + + BVolume volume(VolumeAt(fCurrentVolumeIndex)); + fQuery.Clear(); + fQuery.SetPredicate(fPredicate.String()); + fQuery.SetVolume(&volume); + + return fQuery.Fetch(); +}