No issues found
Tool | Failure ID | Location | Function | Message | Data |
---|---|---|---|---|---|
clang-analyzer | no-output-found | tracker-module-manager.c | Message(text='Unable to locate XML output from invoke-clang-analyzer') | None |
1 /*
2 * Copyright (C) 2010, Nokia <ivan.frade@nokia.com>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20 #include "config.h"
21
22 #include <string.h>
23
24 #include "tracker-module-manager.h"
25
26 #define EXTRACTOR_FUNCTION "tracker_extract_get_metadata"
27 #define INIT_FUNCTION "tracker_extract_module_init"
28 #define SHUTDOWN_FUNCTION "tracker_extract_module_shutdown"
29
30 typedef struct {
31 const gchar *module_path; /* intern string */
32 GList *patterns;
33 gchar *fallback_rdf_type;
34 } RuleInfo;
35
36 typedef struct {
37 GModule *module;
38 TrackerModuleThreadAwareness thread_awareness;
39 TrackerExtractMetadataFunc extract_func;
40 TrackerExtractInitFunc init_func;
41 TrackerExtractShutdownFunc shutdown_func;
42 guint initialized : 1;
43 } ModuleInfo;
44
45 static GHashTable *modules = NULL;
46 static GHashTable *mimetype_map = NULL;
47 static gboolean initialized = FALSE;
48 static GArray *rules = NULL;
49
50 struct _TrackerMimetypeInfo {
51 const GList *rules;
52 const GList *cur;
53
54 ModuleInfo *cur_module_info;
55 };
56
57 static gboolean
58 load_extractor_rule (GKeyFile *key_file,
59 GError **error)
60 {
61 gchar *module_path, **mimetypes;
62 gsize n_mimetypes, i;
63 RuleInfo rule = { 0 };
64
65 module_path = g_key_file_get_string (key_file, "ExtractorRule", "ModulePath", error);
66
67 if (!module_path) {
68 return FALSE;
69 }
70
71 mimetypes = g_key_file_get_string_list (key_file, "ExtractorRule", "MimeTypes", &n_mimetypes, error);
72
73 if (!mimetypes) {
74 g_free (module_path);
75 return FALSE;
76 }
77
78 rule.fallback_rdf_type = g_key_file_get_string (key_file, "ExtractorRule", "FallbackRdfType", NULL);
79
80 /* Construct the rule */
81 rule.module_path = g_intern_string (module_path);
82
83 for (i = 0; i < n_mimetypes; i++) {
84 GPatternSpec *pattern;
85
86 pattern = g_pattern_spec_new (mimetypes[i]);
87 rule.patterns = g_list_prepend (rule.patterns, pattern);
88 }
89
90 if (G_UNLIKELY (!rules)) {
91 rules = g_array_new (FALSE, TRUE, sizeof (RuleInfo));
92 }
93
94 g_array_append_val (rules, rule);
95 g_strfreev (mimetypes);
96 g_free (module_path);
97
98 return TRUE;
99 }
100
101 gboolean
102 tracker_extract_module_manager_init (void)
103 {
104 const gchar *extractors_dir, *name;
105 GList *files = NULL, *l;
106 GError *error = NULL;
107 GDir *dir;
108
109 if (initialized) {
110 return TRUE;
111 }
112
113 if (!g_module_supported ()) {
114 g_error ("Modules are not supported for this platform");
115 return FALSE;
116 }
117
118 extractors_dir = g_getenv ("TRACKER_EXTRACTOR_RULES_DIR");
119 if (G_LIKELY (extractors_dir == NULL)) {
120 extractors_dir = TRACKER_EXTRACTOR_RULES_DIR;
121 } else {
122 g_message ("Extractor rules directory is '%s' (set in env)", extractors_dir);
123 }
124
125 dir = g_dir_open (extractors_dir, 0, &error);
126
127 if (!dir) {
128 g_error ("Error opening extractor rules directory: %s", error->message);
129 g_error_free (error);
130 return FALSE;
131 }
132
133 while ((name = g_dir_read_name (dir)) != NULL) {
134 files = g_list_insert_sorted (files, (gpointer) name, (GCompareFunc) g_strcmp0);
135 }
136
137 g_message ("Loading extractor rules... (%s)", extractors_dir);
138
139 for (l = files; l; l = l->next) {
140 GKeyFile *key_file;
141 const gchar *name;
142 gchar *path;
143
144 name = l->data;
145
146 if (!g_str_has_suffix (l->data, ".rule")) {
147 g_message (" Skipping file '%s', no '.rule' suffix", name);
148 continue;
149 }
150
151 path = g_build_filename (extractors_dir, name, NULL);
152 key_file = g_key_file_new ();
153
154 if (!g_key_file_load_from_file (key_file, path, G_KEY_FILE_NONE, &error) ||
155 !load_extractor_rule (key_file, &error)) {
156 g_warning (" Could not load extractor rule file '%s': %s", name, error->message);
157 g_clear_error (&error);
158 continue;
159 }
160
161 g_debug (" Loaded rule '%s'", name);
162
163 g_key_file_free (key_file);
164 g_free (path);
165 }
166
167 g_message ("Extractor rules loaded");
168 g_list_free (files);
169 g_dir_close (dir);
170
171 /* Initialize miscellaneous data */
172 mimetype_map = g_hash_table_new_full (g_str_hash,
173 g_str_equal,
174 (GDestroyNotify) g_free,
175 NULL);
176 initialized = TRUE;
177
178 return TRUE;
179 }
180
181 static GList *
182 lookup_rules (const gchar *mimetype)
183 {
184 GList *mimetype_rules = NULL;
185 RuleInfo *info;
186 gchar *reversed;
187 gint len, i;
188
189 if (!rules) {
190 return NULL;
191 }
192
193 if (mimetype_map) {
194 mimetype_rules = g_hash_table_lookup (mimetype_map, mimetype);
195
196 if (mimetype_rules) {
197 return mimetype_rules;
198 }
199 }
200
201 reversed = g_strdup (mimetype);
202 g_strreverse (reversed);
203 len = strlen (mimetype);
204
205 /* Apply the rules! */
206 for (i = 0; i < rules->len; i++) {
207 GList *l;
208
209 info = &g_array_index (rules, RuleInfo, i);
210
211 for (l = info->patterns; l; l = l->next) {
212 if (g_pattern_match (l->data, len, mimetype, reversed)) {
213 /* Match, store for future queries and return */
214 mimetype_rules = g_list_prepend (mimetype_rules, info);
215 }
216 }
217 }
218
219 if (mimetype_rules) {
220 mimetype_rules = g_list_reverse (mimetype_rules);
221 g_hash_table_insert (mimetype_map, g_strdup (mimetype), mimetype_rules);
222 }
223
224 g_free (reversed);
225
226 return mimetype_rules;
227 }
228
229 GStrv
230 tracker_extract_module_manager_get_fallback_rdf_types (const gchar *mimetype)
231 {
232 GList *l, *list = lookup_rules (mimetype);
233 GArray *res = g_array_new (TRUE, TRUE, sizeof (gchar *));
234 gchar **types;
235
236 for (l = list; l; l = l->next) {
237 RuleInfo *r_info = l->data;
238
239 if (r_info->fallback_rdf_type != NULL) {
240 gchar *val = g_strdup (r_info->fallback_rdf_type);
241 g_array_append_val (res, val);
242 }
243 }
244
245 types = (GStrv) res->data;
246 g_array_free (res, FALSE);
247
248 return types;
249 }
250
251 static ModuleInfo *
252 load_module (RuleInfo *info,
253 gboolean initialize)
254 {
255 ModuleInfo *module_info = NULL;
256
257 if (modules) {
258 module_info = g_hash_table_lookup (modules, info->module_path);
259 }
260
261 if (!module_info) {
262 GModule *module;
263
264 /* Load the module */
265 module = g_module_open (info->module_path, G_MODULE_BIND_LOCAL);
266
267 if (!module) {
268 g_warning ("Could not load module '%s': %s",
269 info->module_path,
270 g_module_error ());
271 return NULL;
272 }
273
274 g_module_make_resident (module);
275
276 module_info = g_slice_new0 (ModuleInfo);
277 module_info->module = module;
278
279 if (!g_module_symbol (module, EXTRACTOR_FUNCTION, (gpointer *) &module_info->extract_func)) {
280 g_warning ("Could not load module '%s': Function %s() was not found, is it exported?",
281 g_module_name (module), EXTRACTOR_FUNCTION);
282 g_slice_free (ModuleInfo, module_info);
283 return NULL;
284 }
285
286 g_module_symbol (module, INIT_FUNCTION, (gpointer *) &module_info->init_func);
287 g_module_symbol (module, SHUTDOWN_FUNCTION, (gpointer *) &module_info->shutdown_func);
288
289 /* Add it to the cache */
290 if (G_UNLIKELY (!modules)) {
291 /* Key is an intern string, so
292 * pointer comparison suffices
293 */
294 modules = g_hash_table_new (NULL, NULL);
295 }
296
297 g_hash_table_insert (modules, (gpointer) info->module_path, module_info);
298 }
299
300 if (module_info && initialize &&
301 !module_info->initialized) {
302 if (module_info->init_func) {
303 GError *error = NULL;
304
305 if (!(module_info->init_func) (&module_info->thread_awareness, &error)) {
306 g_critical ("Could not initialize module %s: %s",
307 g_module_name (module_info->module),
308 (error) ? error->message : "No error given");
309
310 if (error) {
311 g_error_free (error);
312 }
313
314 return NULL;
315 }
316 } else {
317 module_info->thread_awareness = TRACKER_MODULE_MAIN_THREAD;
318 }
319
320 module_info->initialized = TRUE;
321 }
322
323 return module_info;
324 }
325
326 GModule *
327 tracker_extract_module_manager_get_for_mimetype (const gchar *mimetype,
328 TrackerExtractInitFunc *init_func,
329 TrackerExtractShutdownFunc *shutdown_func,
330 TrackerExtractMetadataFunc *extract_func)
331 {
332 ModuleInfo *module_info = NULL;
333 GList *mimetype_rules;
334
335 if (init_func) {
336 *init_func = NULL;
337 }
338
339 if (shutdown_func) {
340 *shutdown_func = NULL;
341 }
342
343 if (extract_func) {
344 *extract_func = NULL;
345 }
346
347 if (!initialized &&
348 !tracker_extract_module_manager_init ()) {
349 return NULL;
350 }
351
352 mimetype_rules = lookup_rules (mimetype);
353
354 if (!mimetype_rules) {
355 return NULL;
356 }
357
358 module_info = load_module (mimetype_rules->data, FALSE);
359
360 if (!module_info) {
361 return NULL;
362 }
363
364 if (extract_func) {
365 *extract_func = module_info->extract_func;
366 }
367
368 if (init_func) {
369 *init_func = module_info->init_func;
370 }
371
372 if (shutdown_func) {
373 *shutdown_func = module_info->shutdown_func;
374 }
375
376 return module_info->module;
377 }
378
379 gboolean
380 tracker_extract_module_manager_mimetype_is_handled (const gchar *mimetype)
381 {
382 GList *mimetype_rules;
383
384 if (!initialized &&
385 !tracker_extract_module_manager_init ()) {
386 return FALSE;
387 }
388
389 mimetype_rules = lookup_rules (mimetype);
390
391 return mimetype_rules != NULL;
392 }
393
394 static gboolean
395 initialize_first_module (TrackerMimetypeInfo *info)
396 {
397 ModuleInfo *module_info = NULL;
398
399 /* Actually iterates through the list loaded + initialized module */
400 while (info->cur && !module_info) {
401 module_info = load_module (info->cur->data, TRUE);
402
403 if (!module_info) {
404 info->cur = info->cur->next;
405 }
406 }
407
408 info->cur_module_info = module_info;
409 return (info->cur_module_info != NULL);
410 }
411
412 /**
413 * tracker_extract_module_manager_get_mimetype_handlers:
414 * @mimetype: a mimetype string
415 *
416 * Returns a #TrackerMimetypeInfo struct containing information about
417 * the modules that handle @mimetype, or %NULL if no modules handle
418 * @mimetype.
419 *
420 * The modules are ordered from most to least specific, and the
421 * returned #TrackerMimetypeInfo already points to the first
422 * module.
423 *
424 * Returns: (transfer full): (free-function: tracker_mimetype_info_free): (allow-none):
425 * A #TrackerMimetypeInfo holding the information about the different
426 * modules handling @mimetype, or %NULL if no modules handle @mimetype.
427 *
428 * Since: 0.12
429 **/
430 TrackerMimetypeInfo *
431 tracker_extract_module_manager_get_mimetype_handlers (const gchar *mimetype)
432 {
433 TrackerMimetypeInfo *info;
434 GList *mimetype_rules;
435
436 g_return_val_if_fail (mimetype != NULL, NULL);
437
438 mimetype_rules = lookup_rules (mimetype);
439
440 if (!mimetype_rules) {
441 return NULL;
442 }
443
444 info = g_slice_new0 (TrackerMimetypeInfo);
445 info->rules = mimetype_rules;
446 info->cur = info->rules;
447
448 if (!initialize_first_module (info)) {
449 tracker_mimetype_info_free (info);
450 info = NULL;
451 }
452
453 return info;
454 }
455
456 /**
457 * tracker_mimetype_info_get_module:
458 * @info: a #TrackerMimetypeInfo
459 * @extract_func: (out): (allow-none): return value for the extraction function
460 * @thread_awareness: (out): (allow-none): thread awareness of the extractor module
461 *
462 * Returns the #GModule that @info is currently pointing to, if @extract_func is
463 * not %NULL, it will be filled in with the pointer to the metadata extraction
464 * function. If @thread_awareness is not %NULL, it will be filled in with the
465 * module thread awareness description.
466 *
467 * Returns: The %GModule currently pointed to by @info.
468 *
469 * Since: 0.12
470 **/
471 GModule *
472 tracker_mimetype_info_get_module (TrackerMimetypeInfo *info,
473 TrackerExtractMetadataFunc *extract_func,
474 TrackerModuleThreadAwareness *thread_awareness)
475 {
476 g_return_val_if_fail (info != NULL, NULL);
477
478 if (!info->cur_module_info) {
479 return NULL;
480 }
481
482 if (extract_func) {
483 *extract_func = info->cur_module_info->extract_func;
484 }
485
486 if (thread_awareness) {
487 *thread_awareness = info->cur_module_info->thread_awareness;
488 }
489
490 return info->cur_module_info->module;
491 }
492
493 /**
494 * tracker_mimetype_info_iter_next:
495 * @info: a #TrackerMimetypeInfo
496 *
497 * Iterates to the next module handling the mimetype.
498 *
499 * Returns: %TRUE if there is a next module.
500 *
501 * Since: 0.12
502 **/
503 gboolean
504 tracker_mimetype_info_iter_next (TrackerMimetypeInfo *info)
505 {
506 g_return_val_if_fail (info != NULL, FALSE);
507
508 if (info->cur->next) {
509 info->cur = info->cur->next;
510 return initialize_first_module (info);
511 }
512
513 return FALSE;
514 }
515
516 void
517 tracker_mimetype_info_free (TrackerMimetypeInfo *info)
518 {
519 g_return_if_fail (info != NULL);
520
521 g_slice_free (TrackerMimetypeInfo, info);
522 }