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 22 const char* kAttrQueryString = "_trk/qrystr"; 23 const char* kAttrQueryVolume = "_trk/qryvol1"; 24 25 26 BQueryFile::BQueryFile(const entry_ref& ref) 27 { 28 SetTo(ref); 29 } 30 31 32 BQueryFile::BQueryFile(const BEntry& entry) 33 { 34 SetTo(entry); 35 } 36 37 38 BQueryFile::BQueryFile(const char* path) 39 { 40 SetTo(path); 41 } 42 43 44 BQueryFile::BQueryFile(BQuery& query) 45 { 46 SetTo(query); 47 } 48 49 50 BQueryFile::~BQueryFile() 51 { 52 } 53 54 55 status_t 56 BQueryFile::InitCheck() const 57 { 58 return fStatus; 59 } 60 61 62 status_t 63 BQueryFile::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 121 status_t 122 BQueryFile::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 133 status_t 134 BQueryFile::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 145 status_t 146 BQueryFile::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 161 void 162 BQueryFile::Unset() 163 { 164 fStatus = B_NO_INIT; 165 fCurrentVolumeIndex = -1; 166 fVolumes.MakeEmpty(); 167 fQuery.Clear(); 168 fPredicate = ""; 169 } 170 171 172 status_t 173 BQueryFile::SetPredicate(const char* predicate) 174 { 175 fPredicate = predicate; 176 return B_OK; 177 } 178 179 180 status_t 181 BQueryFile::AddVolume(const BVolume& volume) 182 { 183 return fVolumes.AddItem((void*)(addr_t)volume.Device()) ? B_OK : B_NO_MEMORY; 184 } 185 186 187 status_t 188 BQueryFile::AddVolume(dev_t device) 189 { 190 return fVolumes.AddItem((void*)(addr_t)device) ? B_OK : B_NO_MEMORY; 191 } 192 193 194 const char* 195 BQueryFile::Predicate() const 196 { 197 return fPredicate.String(); 198 } 199 200 201 int32 202 BQueryFile::CountVolumes() const 203 { 204 return fVolumes.CountItems(); 205 } 206 207 208 dev_t 209 BQueryFile::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 218 status_t 219 BQueryFile::WriteTo(const entry_ref& ref) 220 { 221 // TODO: implement 222 return B_NOT_SUPPORTED; 223 } 224 225 226 status_t 227 BQueryFile::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 241 status_t 242 BQueryFile::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 268 status_t 269 BQueryFile::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 295 int32 296 BQueryFile::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 322 status_t 323 BQueryFile::Rewind() 324 { 325 fCurrentVolumeIndex = -1; 326 return B_OK; 327 } 328 329 330 int32 331 BQueryFile::CountEntries() 332 { 333 // not supported 334 return -1; 335 } 336 337 338 /*static*/ const char* 339 BQueryFile::MimeType() 340 { 341 return B_QUERY_MIMETYPE; 342 } 343 344 345 status_t 346 BQueryFile::_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