tracker-0.16.2/src/libtracker-extract/tracker-module-manager.c

No issues found

Incomplete coverage

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
Failure running clang-analyzer ('no-output-found')
Message
Unable to locate XML output from invoke-clang-analyzer
  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 }