tracker-0.16.2/src/libtracker-miner/tracker-file-system.c

Location Tool Test ID Function Issue
tracker-file-system.c:828:6 clang-analyzer Branch condition evaluates to a garbage value
  1 /*
  2  * Copyright (C) 2011, 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  * Author: Carlos Garnacho  <carlos@lanedo.com>
 20  */
 21 
 22 #include <string.h>
 23 #include <stdlib.h>
 24 
 25 #include "tracker-file-system.h"
 26 
 27 typedef struct _TrackerFileSystemPrivate TrackerFileSystemPrivate;
 28 typedef struct _FileNodeProperty FileNodeProperty;
 29 typedef struct _FileNodeData FileNodeData;
 30 typedef struct _NodeLookupData NodeLookupData;
 31 
 32 static GHashTable *properties = NULL;
 33 
 34 struct _TrackerFileSystemPrivate {
 35 	GNode *file_tree;
 36 };
 37 
 38 struct _FileNodeProperty {
 39 	GQuark prop_quark;
 40 	gpointer value;
 41 };
 42 
 43 struct _FileNodeData {
 44 	GFile *file;
 45 	gchar *uri_suffix;
 46 	GArray *properties;
 47 	guint shallow   : 1;
 48 	guint unowned : 1;
 49 	guint file_type : 4;
 50 };
 51 
 52 struct _NodeLookupData {
 53 	TrackerFileSystem *file_system;
 54 	GNode *node;
 55 };
 56 
 57 static GQuark quark_file_node = 0;
 58 
 59 static void file_weak_ref_notify (gpointer  user_data,
 60                                   GObject  *prev_location);
 61 
 62 G_DEFINE_TYPE (TrackerFileSystem, tracker_file_system, G_TYPE_OBJECT)
 63 
 64 /*
 65  * TrackerFileSystem is a filesystem abstraction, it mainly serves 2 purposes:
 66  *   - Canonicalizes GFiles, so it is possible later to perform pointer
 67  *     comparisons on them.
 68  *   - Stores data for the GFile lifetime, so it may be used as cache store
 69  *     as long as some file is needed.
 70  *
 71  * The TrackerFileSystem holds a reference on each GFile. There are two cases
 72  * when we want to force a cached GFile to be freed: when it no longer exists
 73  * on disk, and once crawling a directory has completed and we only need to
 74  * remember the directories. Objects may persist in the cache even after
 75  * tracker_file_system_forget_files() is called to delete them if there are
 76  * references held on them elsewhere, and they will stay until all references
 77  * are dropped.
 78  */
 79 
 80 
 81 static void
 82 file_node_data_free (FileNodeData *data,
 83                      GNode        *node)
 84 {
 85 	guint i;
 86 
 87 	if (data->file) {
 88 		if (!data->shallow) {
 89 			g_object_weak_unref (G_OBJECT (data->file),
 90 			                     file_weak_ref_notify,
 91 			                     node);
 92 		}
 93 
 94 		if (!data->unowned) {
 95 			g_object_unref (data->file);
 96 		}
 97 	}
 98 
 99 	data->file = NULL;
100 	g_free (data->uri_suffix);
101 
102 	for (i = 0; i < data->properties->len; i++) {
103 		FileNodeProperty *property;
104 		GDestroyNotify destroy_notify;
105 
106 		property = &g_array_index (data->properties,
107 		                           FileNodeProperty, i);
108 
109 		destroy_notify = g_hash_table_lookup (properties,
110 		                                      GUINT_TO_POINTER (property->prop_quark));
111 
112 		if (destroy_notify) {
113 			(destroy_notify) (property->value);
114 		}
115 	}
116 
117 	g_array_free (data->properties, TRUE);
118 	g_slice_free (FileNodeData, data);
119 }
120 
121 static FileNodeData *
122 file_node_data_new (TrackerFileSystem *file_system,
123                     GFile             *file,
124                     GFileType          file_type,
125                     GNode             *node)
126 {
127 	FileNodeData *data;
128 	NodeLookupData lookup_data;
129 	GArray *node_data;
130 
131 	data = g_slice_new0 (FileNodeData);
132 	data->file = g_object_ref (file);
133 	data->file_type = file_type;
134 	data->properties = g_array_new (FALSE, TRUE, sizeof (FileNodeProperty));
135 
136 	/* We use weak refs to keep track of files */
137 	g_object_weak_ref (G_OBJECT (data->file), file_weak_ref_notify, node);
138 
139 	node_data = g_object_get_qdata (G_OBJECT (data->file),
140 	                                quark_file_node);
141 
142 	if (!node_data) {
143 		node_data = g_array_new (FALSE, FALSE, sizeof (NodeLookupData));
144 		g_object_set_qdata_full (G_OBJECT (data->file),
145 		                         quark_file_node,
146 		                         node_data,
147 		                         (GDestroyNotify) g_array_unref);
148 	}
149 
150 	lookup_data.file_system = file_system;
151 	lookup_data.node = node;
152 	g_array_append_val (node_data, lookup_data);
153 
154 	g_assert (node->data == NULL);
155 	node->data = data;
156 
157 	return data;
158 }
159 
160 static FileNodeData *
161 file_node_data_root_new (void)
162 {
163 	FileNodeData *data;
164 
165 	data = g_slice_new0 (FileNodeData);
166 	data->uri_suffix = g_strdup ("file:///");
167 	data->file = g_file_new_for_uri (data->uri_suffix);
168 	data->properties = g_array_new (FALSE, TRUE, sizeof (FileNodeProperty));
169 	data->file_type = G_FILE_TYPE_DIRECTORY;
170 	data->shallow = TRUE;
171 
172 	return data;
173 }
174 
175 static gboolean
176 file_node_data_equal_or_child (GNode  *node,
177                                gchar  *uri_suffix,
178                                gchar **uri_remainder)
179 {
180 	FileNodeData *data;
181 	gsize len;
182 
183 	data = node->data;
184 	len = strlen (data->uri_suffix);
185 
186 	if (strncmp (uri_suffix, data->uri_suffix, len) == 0) {
187 		uri_suffix += len;
188 
189 		if (uri_suffix[0] == '/') {
190 			uri_suffix++;
191 		} else if (uri_suffix[0] != '\0' &&
192 		           (len < 4 ||
193 		            strcmp (data->uri_suffix + len - 4, ":///") != 0)) {
194 			/* If the first char isn't an uri separator
195 			 * nor \0, node represents a similarly named
196 			 * file, but not a parent after all.
197 			 */
198 			return FALSE;
199 		}
200 
201 		if (uri_remainder) {
202 			*uri_remainder = uri_suffix;
203 		}
204 
205 		return TRUE;
206 	} else {
207 		return FALSE;
208 	}
209 }
210 
211 static GNode *
212 file_tree_lookup (GNode     *tree,
213                   GFile     *file,
214                   GNode    **parent_node,
215                   gchar    **uri_remainder)
216 {
217 	GNode *parent, *node_found, *parent_found;
218 	FileNodeData *data;
219 	gchar *uri, *ptr;
220 
221 	uri = ptr = g_file_get_uri (file);
222 	node_found = parent_found = NULL;
223 
224 	/* Run through the filesystem tree, comparing chunks of
225 	 * uri with the uri suffix in the file nodes, this would
226 	 * get us to the closest registered parent, or the file
227 	 * itself.
228 	 */
229 
230 	if (parent_node) {
231 		*parent_node = NULL;
232 	}
233 
234 	if (uri_remainder) {
235 		*uri_remainder = NULL;
236 	}
237 
238 	if (!tree) {
239 		return NULL;
240 	}
241 
242 	if (!G_NODE_IS_ROOT (tree)) {
243 		FileNodeData *parent_data;
244 		gchar *parent_uri;
245 
246 		parent_data = tree->data;
247 		parent_uri = g_file_get_uri (parent_data->file);
248 
249 		/* Sanity check */
250 		if (!g_str_has_prefix (uri, parent_uri)) {
251 			g_free (parent_uri);
252 			return NULL;
253 		}
254 
255 		ptr += strlen (parent_uri);
256 
257 		g_assert (ptr[0] == '/');
258 		ptr++;
259 
260 		g_free (parent_uri);
261 	} else {
262 		/* First check the root node */
263 		if (!file_node_data_equal_or_child (tree, uri, &ptr)) {
264 			g_free (uri);
265 			return NULL;
266 		}
267 
268 		/* Second check there is no basename and if there isn't,
269 		 * then this node MUST be the closest registered node
270 		 * we can use for the uri. The difference here is that
271 		 * we return tree not NULL.
272 		 */
273 		else if (ptr[0] == '\0') {
274 			g_free (uri);
275 			return tree;
276                 }
277 	}
278 
279 	parent = tree;
280 
281 	while (parent) {
282 		GNode *child, *next = NULL;
283 		gchar *ret_ptr;
284 
285 		for (child = g_node_first_child (parent);
286 		     child != NULL;
287 		     child = g_node_next_sibling (child)) {
288 			data = child->data;
289 
290 			if (data->uri_suffix[0] != ptr[0])
291 				continue;
292 
293 			if (file_node_data_equal_or_child (child, ptr, &ret_ptr)) {
294 				ptr = ret_ptr;
295 				next = child;
296 				break;
297 			}
298 		}
299 
300 		if (next) {
301 			if (ptr[0] == '\0') {
302 				/* Exact match */
303 				node_found = next;
304 				parent_found = parent;
305 				break;
306 			} else {
307 				/* Descent down the child */
308 				parent = next;
309 			}
310 		} else {
311 			parent_found = parent;
312 			break;
313 		}
314 	}
315 
316 	if (parent_node) {
317 		*parent_node = parent_found;
318 	}
319 
320 	if (ptr && *ptr && uri_remainder) {
321 		*uri_remainder = g_strdup (ptr);
322 	}
323 
324 	g_free (uri);
325 
326 	return node_found;
327 }
328 
329 static gboolean
330 file_tree_free_node_foreach (GNode    *node,
331                              gpointer  user_data)
332 {
333 	file_node_data_free (node->data, node);
334 	return FALSE;
335 }
336 
337 /* TrackerFileSystem implementation */
338 
339 static void
340 tracker_file_system_finalize (GObject *object)
341 {
342 	TrackerFileSystemPrivate *priv;
343 
344 	priv = TRACKER_FILE_SYSTEM (object)->priv;
345 
346 	g_node_traverse (priv->file_tree,
347 	                 G_POST_ORDER,
348 	                 G_TRAVERSE_ALL, -1,
349 	                 file_tree_free_node_foreach,
350 	                 NULL);
351 	g_node_destroy (priv->file_tree);
352 
353 	G_OBJECT_CLASS (tracker_file_system_parent_class)->finalize (object);
354 }
355 
356 static void
357 tracker_file_system_class_init (TrackerFileSystemClass *klass)
358 {
359 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
360 
361 	object_class->finalize = tracker_file_system_finalize;
362 
363 	g_type_class_add_private (object_class,
364 	                          sizeof (TrackerFileSystemPrivate));
365 
366 	quark_file_node =
367 		g_quark_from_static_string ("tracker-quark-file-node");
368 }
369 static void
370 tracker_file_system_init (TrackerFileSystem *file_system)
371 {
372 	TrackerFileSystemPrivate *priv;
373 	FileNodeData *root_data;
374 
375 	file_system->priv = priv =
376 		G_TYPE_INSTANCE_GET_PRIVATE (file_system,
377 		                             TRACKER_TYPE_FILE_SYSTEM,
378 		                             TrackerFileSystemPrivate);
379 
380 	root_data = file_node_data_root_new ();
381 	priv->file_tree = g_node_new (root_data);
382 }
383 
384 TrackerFileSystem *
385 tracker_file_system_new (void)
386 {
387 	return g_object_new (TRACKER_TYPE_FILE_SYSTEM, NULL);
388 }
389 
390 static void
391 reparent_child_nodes_to_parent (GNode *node)
392 {
393 	FileNodeData *node_data;
394 	GNode *child, *parent;
395 
396 	if (!node->parent) {
397 		return;
398 	}
399 
400 	parent = node->parent;
401 	node_data = node->data;
402 	child = g_node_first_child (node);
403 
404 	while (child) {
405 		FileNodeData *data;
406 		gchar *uri_suffix;
407 		GNode *cur;
408 
409 		cur = child;
410 		data = cur->data;
411 		child = g_node_next_sibling (child);
412 
413 		uri_suffix = g_strdup_printf ("%s/%s",
414 					      node_data->uri_suffix,
415 					      data->uri_suffix);
416 
417 		g_free (data->uri_suffix);
418 		data->uri_suffix = uri_suffix;
419 
420 		g_node_unlink (cur);
421 		g_node_prepend (parent, cur);
422 	}
423 }
424 
425 static void
426 file_weak_ref_notify (gpointer  user_data,
427                       GObject  *prev_location)
428 {
429 	FileNodeData *data;
430 	GNode *node;
431 
432 	node = user_data;
433 	data = node->data;
434 
435 	g_assert (data->file == (GFile *) prev_location);
436 
437 	data->file = NULL;
438 	reparent_child_nodes_to_parent (node);
439 
440 	/* Delete node tree here */
441 	file_node_data_free (data, NULL);
442 	g_node_destroy (node);
443 }
444 
445 static GNode *
446 file_system_get_node (TrackerFileSystem *file_system,
447                       GFile             *file)
448 {
449 	TrackerFileSystemPrivate *priv;
450 	GArray *node_data;
451 	GNode *node = NULL;
452 
453 	node_data = g_object_get_qdata (G_OBJECT (file), quark_file_node);
454 
455 	if (node_data) {
456 		NodeLookupData *cur;
457 		guint i;
458 
459 		for (i = 0; i < node_data->len; i++) {
460 			cur = &g_array_index (node_data, NodeLookupData, i);
461 
462 			if (cur->file_system == file_system) {
463 				node = cur->node;
464 			}
465 		}
466 	}
467 
468 	if (!node) {
469 		priv = file_system->priv;
470 		node = file_tree_lookup (priv->file_tree, file,
471 		                         NULL, NULL);
472 	}
473 
474 	return node;
475 }
476 
477 GFile *
478 tracker_file_system_get_file (TrackerFileSystem *file_system,
479                               GFile             *file,
480                               GFileType          file_type,
481                               GFile             *parent)
482 {
483 	TrackerFileSystemPrivate *priv;
484 	FileNodeData *data;
485 	GNode *node, *parent_node;
486 	gchar *uri_suffix = NULL;
487 
488 	g_return_val_if_fail (G_IS_FILE (file), NULL);
489 	g_return_val_if_fail (TRACKER_IS_FILE_SYSTEM (file_system), NULL);
490 
491 	priv = file_system->priv;
492 	node = NULL;
493 	parent_node = NULL;
494 
495 	if (parent) {
496 		parent_node = file_system_get_node (file_system, parent);
497 		node = file_tree_lookup (parent_node, file,
498 		                         NULL, &uri_suffix);
499 	} else {
500 		node = file_tree_lookup (priv->file_tree, file,
501 		                         &parent_node, &uri_suffix);
502 	}
503 
504 	if (!node) {
505 		if (!parent_node) {
506 			gchar *uri;
507 
508 			uri = g_file_get_uri (file);
509 			g_warning ("Could not find parent node for URI:'%s'", uri);
510 			g_warning ("NOTE: URI themes other than 'file://' are not supported currently.");
511 			g_free (uri);
512 
513 			return NULL;
514 		}
515 
516 		node = g_node_new (NULL);
517 
518 		/* Parent was found, add file as child */
519 		data = file_node_data_new (file_system, file,
520 		                           file_type, node);
521 		data->uri_suffix = uri_suffix;
522 
523 		g_node_append (parent_node, node);
524 	} else {
525 		data = node->data;
526 		g_free (uri_suffix);
527 
528 		/* Update file type if it was unknown */
529 		if (data->file_type == G_FILE_TYPE_UNKNOWN) {
530 			data->file_type = file_type;
531 		}
532 	}
533 
534 	return data->file;
535 }
536 
537 GFile *
538 tracker_file_system_peek_file (TrackerFileSystem *file_system,
539                                GFile             *file)
540 {
541 	GNode *node;
542 
543 	g_return_val_if_fail (G_IS_FILE (file), NULL);
544 	g_return_val_if_fail (TRACKER_IS_FILE_SYSTEM (file_system), NULL);
545 
546 	node = file_system_get_node (file_system, file);
547 
548 	if (node) {
549 		FileNodeData *data;
550 
551 		data = node->data;
552 		return data->file;
553 	}
554 
555 	return NULL;
556 }
557 
558 GFile *
559 tracker_file_system_peek_parent (TrackerFileSystem *file_system,
560                                  GFile             *file)
561 {
562 	GNode *node;
563 
564 	g_return_val_if_fail (file != NULL, NULL);
565 	g_return_val_if_fail (TRACKER_IS_FILE_SYSTEM (file_system), NULL);
566 
567 	node = file_system_get_node (file_system, file);
568 
569 	if (node) {
570 		FileNodeData *parent_data;
571 		GNode *parent;
572 
573 		parent = node->parent;
574 		parent_data = parent->data;
575 
576 		return parent_data->file;
577 	}
578 
579 	return NULL;
580 }
581 
582 typedef struct {
583 	TrackerFileSystemTraverseFunc func;
584 	gpointer user_data;
585 	GSList *ignore_children;
586 } TraverseData;
587 
588 static gint
589 node_is_child_of_ignored (gconstpointer a,
590                           gconstpointer b)
591 {
592 	if (g_node_is_ancestor ((GNode *) a, (GNode *) b))
593 		return 0;
594 
595 	return 1;
596 }
597 
598 static gboolean
599 traverse_filesystem_func (GNode    *node,
600                           gpointer  user_data)
601 {
602 	TraverseData *data = user_data;
603 	FileNodeData *node_data;
604 	gboolean retval = FALSE;
605 
606 	node_data = node->data;
607 
608 	if (!data->ignore_children ||
609 	    !g_slist_find_custom (data->ignore_children,
610 	                          node, node_is_child_of_ignored)) {
611 		/* This node isn't a child of an
612 		 * ignored one, execute callback
613 		 */
614 		retval = data->func (node_data->file, data->user_data);
615 	}
616 
617 	/* Avoid recursing within the children of this node */
618 	if (retval) {
619 		data->ignore_children = g_slist_prepend (data->ignore_children,
620 		                                         node);
621 	}
622 
623 	return FALSE;
624 }
625 
626 void
627 tracker_file_system_traverse (TrackerFileSystem             *file_system,
628                               GFile                         *root,
629                               GTraverseType                  order,
630                               TrackerFileSystemTraverseFunc  func,
631                               gpointer                       user_data)
632 {
633 	TrackerFileSystemPrivate *priv;
634 	TraverseData data;
635 	GNode *node;
636 
637 	g_return_if_fail (TRACKER_IS_FILE_SYSTEM (file_system));
638 	g_return_if_fail (func != NULL);
639 
640 	priv = file_system->priv;
641 
642 	if (root) {
643 		node = file_system_get_node (file_system, root);
644 	} else {
645 		node = priv->file_tree;
646 	}
647 
648 	data.func = func;
649 	data.user_data = user_data;
650 	data.ignore_children = NULL;
651 
652 	g_node_traverse (node,
653 	                 order,
654 	                 G_TRAVERSE_ALL,
655 	                 -1,
656 	                 traverse_filesystem_func,
657 	                 &data);
658 
659 	g_slist_free (data.ignore_children);
660 }
661 
662 void
663 tracker_file_system_register_property (GQuark             prop,
664                                        GDestroyNotify     destroy_notify)
665 {
666 	g_return_if_fail (prop != 0);
667 
668 	if (!properties) {
669 		properties = g_hash_table_new (NULL, NULL);
670 	}
671 
672 	if (g_hash_table_lookup (properties, GUINT_TO_POINTER (prop))) {
673 		g_warning ("FileSystem: property '%s' has been already registered",
674 		           g_quark_to_string (prop));
675 		return;
676 	}
677 
678 	g_hash_table_insert (properties,
679 	                     GUINT_TO_POINTER (prop),
680 	                     destroy_notify);
681 }
682 
683 static int
684 search_property_node (gconstpointer key,
685                       gconstpointer item)
686 {
687 	const FileNodeProperty *key_prop, *prop;
688 
689 	key_prop = key;
690 	prop = item;
691 
692 	if (key_prop->prop_quark < prop->prop_quark)
693 		return -1;
694 	else if (key_prop->prop_quark > prop->prop_quark)
695 		return 1;
696 
697 	return 0;
698 }
699 
700 void
701 tracker_file_system_set_property (TrackerFileSystem *file_system,
702                                   GFile             *file,
703                                   GQuark             prop,
704                                   gpointer           prop_data)
705 {
706 	FileNodeProperty property, *match;
707 	GDestroyNotify destroy_notify;
708 	FileNodeData *data;
709 	GNode *node;
710 
711 	g_return_if_fail (TRACKER_IS_FILE_SYSTEM (file_system));
712 	g_return_if_fail (file != NULL);
713 	g_return_if_fail (prop != 0);
714 
715 	if (!properties ||
716 	    !g_hash_table_lookup_extended (properties,
717 	                                   GUINT_TO_POINTER (prop),
718 	                                   NULL, (gpointer *) &destroy_notify)) {
719 		g_warning ("FileSystem: property '%s' is not registered",
720 		           g_quark_to_string (prop));
721 		return;
722 	}
723 
724 	node = file_system_get_node (file_system, file);
725 	g_return_if_fail (node != NULL);
726 
727 	data = node->data;
728 
729 	property.prop_quark = prop;
730 	match = bsearch (&property, data->properties->data,
731 	                 data->properties->len, sizeof (FileNodeProperty),
732 	                 search_property_node);
733 
734 	if (match) {
735 		if (destroy_notify) {
736 			(destroy_notify) (match->value);
737 		}
738 
739 		match->value = prop_data;
740 	} else {
741 		FileNodeProperty *item;
742 		guint i;
743 
744 		/* No match, insert new element */
745 		for (i = 0; i < data->properties->len; i++) {
746 			item = &g_array_index (data->properties,
747 			                       FileNodeProperty, i);
748 
749 			if (item->prop_quark > prop) {
750 				break;
751 			}
752 		}
753 
754 		property.value = prop_data;
755 
756 		if (i >= data->properties->len) {
757 			g_array_append_val (data->properties, property);
758 		} else {
759 			g_array_insert_val (data->properties, i, property);
760 		}
761 	}
762 }
763 
764 gpointer
765 tracker_file_system_get_property (TrackerFileSystem *file_system,
766                                   GFile             *file,
767                                   GQuark             prop)
768 {
769 	FileNodeData *data;
770 	FileNodeProperty property, *match;
771 	GNode *node;
772 
773 	g_return_val_if_fail (TRACKER_IS_FILE_SYSTEM (file_system), NULL);
774 	g_return_val_if_fail (file != NULL, NULL);
775 	g_return_val_if_fail (prop > 0, NULL);
776 
777 	node = file_system_get_node (file_system, file);
778 	g_return_val_if_fail (node != NULL, NULL);
779 
780 	data = node->data;
781 	property.prop_quark = prop;
782 
783 	match = bsearch (&property, data->properties->data,
784 	                 data->properties->len, sizeof (FileNodeProperty),
785 	                 search_property_node);
786 
787 	return (match) ? match->value : NULL;
788 }
789 
790 void
791 tracker_file_system_unset_property (TrackerFileSystem *file_system,
792                                     GFile             *file,
793                                     GQuark             prop)
794 {
795 	FileNodeData *data;
796 	FileNodeProperty property, *match;
797 	GDestroyNotify destroy_notify;
798 	GNode *node;
799 	guint index;
800 
801 	g_return_if_fail (TRACKER_IS_FILE_SYSTEM (file_system));
802 	g_return_if_fail (file != NULL);
803 	g_return_if_fail (prop > 0);
804 
805 	if (!properties ||
806 	    !g_hash_table_lookup_extended (properties,
807 	                                   GUINT_TO_POINTER (prop),
808 	                                   NULL,
809 	                                   (gpointer *) &destroy_notify)) {
810 		g_warning ("FileSystem: property '%s' is not registered",
811 		           g_quark_to_string (prop));
812 	}
813 
814 	node = file_system_get_node (file_system, file);
815 	g_return_if_fail (node != NULL);
816 
817 	data = node->data;
818 	property.prop_quark = prop;
819 
820 	match = bsearch (&property, data->properties->data,
821 	                 data->properties->len, sizeof (FileNodeProperty),
822 	                 search_property_node);
823 
824 	if (!match) {
825 		return;
826 	}
827 
828 	if (destroy_notify) {
Branch condition evaluates to a garbage value
(emitted by clang-analyzer)

TODO: a detailed trace is available in the data model (not yet rendered in this report)

829 (destroy_notify) (match->value); 830 } 831 832 /* Find out the index from memory positions */ 833 index = (guint) ((FileNodeProperty *) match - 834 (FileNodeProperty *) data->properties->data); 835 g_assert (index >= 0 && index < data->properties->len); 836 837 g_array_remove_index (data->properties, index); 838 } 839 840 typedef struct { 841 TrackerFileSystem *file_system; 842 GList *list; 843 GFileType file_type; 844 } ForgetFilesData; 845 846 static gboolean 847 append_deleted_files (GNode *node, 848 gpointer user_data) 849 { 850 ForgetFilesData *data; 851 FileNodeData *node_data; 852 853 data = user_data; 854 node_data = node->data; 855 856 if (data->file_type == G_FILE_TYPE_UNKNOWN || 857 node_data->file_type == data->file_type) { 858 data->list = g_list_prepend (data->list, node_data); 859 } 860 861 return FALSE; 862 } 863 864 static void 865 forget_file (FileNodeData *node_data) 866 { 867 if (!node_data->unowned) { 868 node_data->unowned = TRUE; 869 870 /* Weak reference handler will remove the file from the tree and 871 * clean up node_data if this is the final reference. 872 */ 873 g_object_unref (node_data->file); 874 } 875 } 876 877 void 878 tracker_file_system_forget_files (TrackerFileSystem *file_system, 879 GFile *root, 880 GFileType file_type) 881 { 882 ForgetFilesData data = { file_system, NULL, file_type }; 883 GNode *node; 884 885 g_return_if_fail (TRACKER_IS_FILE_SYSTEM (file_system)); 886 g_return_if_fail (G_IS_FILE (root)); 887 888 node = file_system_get_node (file_system, root); 889 g_return_if_fail (node != NULL); 890 891 /* We need to get the files to delete into a list, so 892 * the node tree isn't modified during traversal. 893 */ 894 g_node_traverse (node, 895 G_PRE_ORDER, 896 (file_type == G_FILE_TYPE_REGULAR) ? 897 G_TRAVERSE_LEAVES : G_TRAVERSE_ALL, 898 -1, append_deleted_files, 899 &data); 900 901 g_list_foreach (data.list, (GFunc) forget_file, NULL); 902 g_list_free (data.list); 903 }