xref: /haiku/src/kits/shared/QueryFile.cpp (revision 820dca4df6c7bf955c46e8f6521b9408f50b2900)
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