1/* 2 * Copyright 2010, Axel D��rfler, axeld@pinc-software.de. 3 * This file may be used under the terms of the MIT License. 4 */ 5 6 7#include <QueryFile.h> 8 9#include <fs_attr.h> 10#include <Volume.h> 11#include <VolumeRoster.h> 12 13#include "tracker/MimeTypes.h" 14#include "tracker/Utilities.h" 15 16 17// TODO: add write support 18// TODO: let Tracker use it? 19// TODO: live query support? 20 21 22const char* kAttrQueryString = "_trk/qrystr"; 23const char* kAttrQueryVolume = "_trk/qryvol1"; 24 25 26BQueryFile::BQueryFile(const entry_ref& ref) 27{ 28 SetTo(ref); 29} 30 31 32BQueryFile::BQueryFile(const BEntry& entry) 33{ 34 SetTo(entry); 35} 36 37 38BQueryFile::BQueryFile(const char* path) 39{ 40 SetTo(path); 41} 42 43 44BQueryFile::BQueryFile(BQuery& query) 45{ 46 SetTo(query); 47} 48 49 50BQueryFile::~BQueryFile() 51{ 52} 53 54 55status_t 56BQueryFile::InitCheck() const 57{ 58 return fStatus; 59} 60 61 62status_t 63BQueryFile::SetTo(const entry_ref& ref) 64{ 65 Unset(); 66 67 BNode node(&ref); 68 fStatus = node.InitCheck(); 69 if (fStatus != B_OK) 70 return fStatus; 71 72 ssize_t bytesRead = node.ReadAttrString(kAttrQueryString, &fPredicate); 73 if (bytesRead < 0) 74 return fStatus = bytesRead; 75 76 bool searchAllVolumes = true; 77 attr_info info; 78 if (node.GetAttrInfo(kAttrQueryVolume, &info) == B_OK) { 79 void* buffer = malloc(info.size); 80 if (buffer == NULL) 81 return fStatus = B_NO_MEMORY; 82 83 BMessage message; 84 fStatus = message.Unflatten((const char*)buffer); 85 if (fStatus == B_OK) { 86 for (int32 index = 0; index < 100; index++) { 87 BVolume volume; 88 status_t status = BPrivate::MatchArchivedVolume(&volume, 89 &message, index); 90 if (status == B_OK) { 91 fStatus = AddVolume(volume); 92 if (fStatus != B_OK) 93 break; 94 95 searchAllVolumes = false; 96 } else if (status != B_DEV_BAD_DRIVE_NUM) { 97 // Volume doesn't seem to be mounted 98 fStatus = status; 99 break; 100 } 101 } 102 } 103 104 free(buffer); 105 } 106 107 if (searchAllVolumes) { 108 // add all volumes to query 109 BVolumeRoster roster; 110 BVolume volume; 111 while (roster.GetNextVolume(&volume) == B_OK) { 112 if (volume.IsPersistent() && volume.KnowsQuery()) 113 AddVolume(volume); 114 } 115 } 116 117 return fStatus; 118} 119 120 121status_t 122BQueryFile::SetTo(const BEntry& entry) 123{ 124 entry_ref ref; 125 fStatus = entry.GetRef(&ref); 126 if (fStatus != B_OK) 127 return fStatus; 128 129 return SetTo(ref); 130} 131 132 133status_t 134BQueryFile::SetTo(const char* path) 135{ 136 entry_ref ref; 137 fStatus = get_ref_for_path(path, &ref); 138 if (fStatus != B_OK) 139 return fStatus; 140 141 return SetTo(ref); 142} 143 144 145status_t 146BQueryFile::SetTo(BQuery& query) 147{ 148 Unset(); 149 150 BString predicate; 151 query.GetPredicate(&predicate); 152 153 fStatus = SetPredicate(predicate.String()); 154 if (fStatus != B_OK) 155 return fStatus; 156 157 return fStatus = AddVolume(query.TargetDevice()); 158} 159 160 161void 162BQueryFile::Unset() 163{ 164 fStatus = B_NO_INIT; 165 fCurrentVolumeIndex = -1; 166 fVolumes.MakeEmpty(); 167 fQuery.Clear(); 168 fPredicate = ""; 169} 170 171 172status_t 173BQueryFile::SetPredicate(const char* predicate) 174{ 175 fPredicate = predicate; 176 return B_OK; 177} 178 179 180status_t 181BQueryFile::AddVolume(const BVolume& volume) 182{ 183 return fVolumes.AddItem((void*)(addr_t)volume.Device()) ? B_OK : B_NO_MEMORY; 184} 185 186 187status_t 188BQueryFile::AddVolume(dev_t device) 189{ 190 return fVolumes.AddItem((void*)(addr_t)device) ? B_OK : B_NO_MEMORY; 191} 192 193 194const char* 195BQueryFile::Predicate() const 196{ 197 return fPredicate.String(); 198} 199 200 201int32 202BQueryFile::CountVolumes() const 203{ 204 return fVolumes.CountItems(); 205} 206 207 208dev_t 209BQueryFile::VolumeAt(int32 index) const 210{ 211 if (index < 0 || index >= fVolumes.CountItems()) 212 return -1; 213 214 return (dev_t)(addr_t)fVolumes.ItemAt(index); 215} 216 217 218status_t 219BQueryFile::WriteTo(const entry_ref& ref) 220{ 221 // TODO: implement 222 return B_NOT_SUPPORTED; 223} 224 225 226status_t 227BQueryFile::WriteTo(const char* path) 228{ 229 entry_ref ref; 230 status_t status = get_ref_for_path(path, &ref); 231 if (status != B_OK) 232 return status; 233 234 return WriteTo(ref); 235} 236 237 238// #pragma mark - BEntryList implementation 239 240 241status_t 242BQueryFile::GetNextEntry(BEntry* entry, bool traverse) 243{ 244 if (fCurrentVolumeIndex == -1) { 245 // Start with first volume 246 fCurrentVolumeIndex = 0; 247 248 status_t status = _SetQuery(0); 249 if (status != B_OK) 250 return status; 251 } 252 253 status_t status = B_ENTRY_NOT_FOUND; 254 255 while (fCurrentVolumeIndex < CountVolumes()) { 256 status = fQuery.GetNextEntry(entry, traverse); 257 if (status != B_ENTRY_NOT_FOUND) 258 break; 259 260 // Continue with next volume, if any 261 status = _SetQuery(++fCurrentVolumeIndex); 262 } 263 264 return status; 265} 266 267 268status_t 269BQueryFile::GetNextRef(entry_ref* ref) 270{ 271 if (fCurrentVolumeIndex == -1) { 272 // Start with first volume 273 fCurrentVolumeIndex = 0; 274 275 status_t status = _SetQuery(0); 276 if (status != B_OK) 277 return status; 278 } 279 280 status_t status = B_ENTRY_NOT_FOUND; 281 282 while (fCurrentVolumeIndex < CountVolumes()) { 283 status = fQuery.GetNextRef(ref); 284 if (status != B_ENTRY_NOT_FOUND) 285 break; 286 287 // Continue with next volume, if any 288 status = _SetQuery(++fCurrentVolumeIndex); 289 } 290 291 return status; 292} 293 294 295int32 296BQueryFile::GetNextDirents(struct dirent* buffer, size_t length, int32 count) 297{ 298 if (fCurrentVolumeIndex == -1) { 299 // Start with first volume 300 fCurrentVolumeIndex = 0; 301 302 status_t status = _SetQuery(0); 303 if (status != B_OK) 304 return status; 305 } 306 307 status_t status = B_ENTRY_NOT_FOUND; 308 309 while (fCurrentVolumeIndex < CountVolumes()) { 310 status = fQuery.GetNextDirents(buffer, length, count); 311 if (status != B_ENTRY_NOT_FOUND) 312 break; 313 314 // Continue with next volume, if any 315 status = _SetQuery(++fCurrentVolumeIndex); 316 } 317 318 return status; 319} 320 321 322status_t 323BQueryFile::Rewind() 324{ 325 fCurrentVolumeIndex = -1; 326 return B_OK; 327} 328 329 330int32 331BQueryFile::CountEntries() 332{ 333 // not supported 334 return -1; 335} 336 337 338/*static*/ const char* 339BQueryFile::MimeType() 340{ 341 return B_QUERY_MIMETYPE; 342} 343 344 345status_t 346BQueryFile::_SetQuery(int32 index) 347{ 348 if (fCurrentVolumeIndex >= CountVolumes()) 349 return B_ENTRY_NOT_FOUND; 350 351 BVolume volume(VolumeAt(fCurrentVolumeIndex)); 352 fQuery.Clear(); 353 fQuery.SetPredicate(fPredicate.String()); 354 fQuery.SetVolume(&volume); 355 356 return fQuery.Fetch(); 357} 358