/* * 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*)(addr_t)volume.Device()) ? B_OK : B_NO_MEMORY; } status_t BQueryFile::AddVolume(dev_t device) { return fVolumes.AddItem((void*)(addr_t)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)(addr_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(); }