split attribute hash initialization into its own function
[platform/upstream/glib.git] / gio / gfileinfo.c
1 /* GIO - GLib Input, Output and Streaming Library
2  * 
3  * Copyright (C) 2006-2007 Red Hat, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General
16  * Public License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18  * Boston, MA 02111-1307, USA.
19  *
20  * Author: Alexander Larsson <alexl@redhat.com>
21  */
22
23 /**
24  * SECTION:gfileinfo
25  * @short_description: File Information and Attributes
26  * @include: gio/gio.h
27  * @see_also: #GFile, <link linkend="gio-GFileAttribute">GFileAttribute</link>
28  * 
29  * Functionality for manipulating basic metadata for files. #GFileInfo
30  * implements methods for getting information that all files should 
31  * contain, and allows for manipulation of extended attributes. 
32  *
33  * See <link linkend="gio-GFileAttribute">GFileAttribute</link> for more
34  * information on how GIO handles file attributes.
35  *
36  * To obtain a #GFileInfo for a #GFile, use g_file_query_info() (or its 
37  * async variant). To obtain a #GFileInfo for a file input or output 
38  * stream, use g_file_input_stream_query_info() or 
39  * g_file_output_stream_query_info() (or their async variants).
40  *
41  * To change the actual attributes of a file, you should then set the 
42  * attribute in the #GFileInfo and call g_file_set_attributes_from_info() 
43  * or g_file_set_attributes_async() on a GFile.
44  *
45  * However, not all attributes can be changed in the file. For instance, 
46  * the actual size of a file cannot be changed via g_file_info_set_size(). 
47  * You may call g_file_query_settable_attributes() and 
48  * g_file_query_writable_namespaces() to discover the settable attributes 
49  * of a particular file at runtime.
50  *
51  * #GFileAttributeMatcher allows for searching through a #GFileInfo for 
52  * attributes.
53  **/
54
55 #include "config.h"
56
57 #include <string.h>
58
59 #include "gfileinfo.h"
60 #include "gfileattribute-priv.h"
61 #include "gicon.h"
62 #include "glibintl.h"
63
64 #include "gioalias.h"
65
66 /* We use this nasty thing, because NULL is a valid attribute matcher (matches nothing) */
67 #define NO_ATTRIBUTE_MASK ((GFileAttributeMatcher *)1)
68
69 typedef struct  {
70   guint32 attribute;
71   GFileAttributeValue value;
72 } GFileAttribute;
73
74 struct _GFileInfo
75 {
76   GObject parent_instance;
77
78   GArray *attributes;
79   GFileAttributeMatcher *mask;
80 };
81
82 struct _GFileInfoClass
83 {
84   GObjectClass parent_class;
85 };
86
87
88 static gboolean g_file_attribute_matcher_matches_id (GFileAttributeMatcher *matcher,
89                                                      guint32 id);
90
91 G_DEFINE_TYPE (GFileInfo, g_file_info, G_TYPE_OBJECT);
92
93 typedef struct {
94   guint32 id;
95   guint32 attribute_id_counter;
96 } NSInfo;
97
98 G_LOCK_DEFINE_STATIC (attribute_hash);
99 static int namespace_id_counter = 0;
100 static GHashTable *ns_hash = NULL;
101 static GHashTable *attribute_hash = NULL;
102 static char ***attributes = NULL;
103
104 /* Attribute ids are 32bit, we split it up like this:
105  * |------------|--------------------|
106  *   12 bit          20 bit       
107  *   namespace      attribute id    
108  *
109  * This way the attributes gets sorted in namespace order
110  */
111
112 #define NS_POS 20
113 #define NS_MASK ((guint32)((1<<12) - 1))
114 #define ID_POS 0
115 #define ID_MASK ((guint32)((1<<20) - 1))
116
117 #define GET_NS(_attr_id) \
118     (((guint32) (_attr_id) >> NS_POS) & NS_MASK)
119 #define GET_ID(_attr_id) \
120     (((guint32)(_attr_id) >> ID_POS) & ID_MASK)
121
122 #define MAKE_ATTR_ID(_ns, _id)                          \
123     ( ((((guint32) _ns) & NS_MASK) << NS_POS) |         \
124       ((((guint32) _id) & ID_MASK) << ID_POS) )
125
126 static NSInfo *
127 _lookup_namespace (const char *namespace)
128 {
129   NSInfo *ns_info;
130   
131   ns_info = g_hash_table_lookup (ns_hash, namespace);
132   if (ns_info == NULL)
133     {
134       ns_info = g_new0 (NSInfo, 1);
135       ns_info->id = ++namespace_id_counter;
136       g_hash_table_insert (ns_hash, g_strdup (namespace), ns_info);
137       attributes = g_realloc (attributes, (ns_info->id + 1) * sizeof (char **));
138       attributes[ns_info->id] = NULL;
139     }
140   return ns_info;
141 }
142
143 static void
144 ensure_attribute_hash (void)
145 {
146   if (attribute_hash != NULL)
147     return;
148
149   ns_hash = g_hash_table_new (g_str_hash, g_str_equal);
150   attribute_hash = g_hash_table_new (g_str_hash, g_str_equal);
151 }
152
153 static guint32
154 lookup_namespace (const char *namespace)
155 {
156   NSInfo *ns_info;
157   guint32 id;
158   
159   G_LOCK (attribute_hash);
160   
161   ensure_attribute_hash ();
162
163   ns_info = _lookup_namespace (namespace);
164   id = 0;
165   if (ns_info)
166     id = ns_info->id;
167   
168   G_UNLOCK (attribute_hash);
169
170   return id;
171 }
172
173 static char *
174 get_attribute_for_id (int attribute)
175 {
176   char *s;
177   G_LOCK (attribute_hash);
178   s = attributes[GET_NS(attribute)][GET_ID(attribute)];
179   G_UNLOCK (attribute_hash);
180   return s;
181 }
182
183 static guint32
184 lookup_attribute (const char *attribute)
185 {
186   guint32 attr_id, id;
187   char *ns;
188   const char *colon;
189   NSInfo *ns_info;
190   
191   G_LOCK (attribute_hash);
192   ensure_attribute_hash ();
193
194   attr_id = GPOINTER_TO_UINT (g_hash_table_lookup (attribute_hash, attribute));
195
196   if (attr_id != 0)
197     {
198       G_UNLOCK (attribute_hash);
199       return attr_id;
200     }
201
202   colon = strstr (attribute, "::");
203   if (colon)
204     ns = g_strndup (attribute, colon - attribute);
205   else
206     ns = g_strdup ("");
207
208   ns_info = _lookup_namespace (ns);
209   g_free (ns);
210
211   id = ++ns_info->attribute_id_counter;
212   attributes[ns_info->id] = g_realloc (attributes[ns_info->id], (id + 1) * sizeof (char *));
213   attributes[ns_info->id][id] = g_strdup (attribute);
214   
215   attr_id = MAKE_ATTR_ID (ns_info->id, id);
216
217   g_hash_table_insert (attribute_hash, attributes[ns_info->id][id], GUINT_TO_POINTER (attr_id));
218   
219   G_UNLOCK (attribute_hash);
220   
221   return attr_id;
222 }
223
224 static void
225 g_file_info_finalize (GObject *object)
226 {
227   GFileInfo *info;
228   int i;
229   GFileAttribute *attrs;
230
231   info = G_FILE_INFO (object);
232
233   attrs = (GFileAttribute *)info->attributes->data;
234   for (i = 0; i < info->attributes->len; i++)
235     _g_file_attribute_value_clear (&attrs[i].value);
236   g_array_free (info->attributes, TRUE);  
237
238   if (info->mask != NO_ATTRIBUTE_MASK)
239     g_file_attribute_matcher_unref (info->mask);
240
241   G_OBJECT_CLASS (g_file_info_parent_class)->finalize (object);
242 }
243
244 static void
245 g_file_info_class_init (GFileInfoClass *klass)
246 {
247   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
248   
249   gobject_class->finalize = g_file_info_finalize;
250 }
251
252 static void
253 g_file_info_init (GFileInfo *info)
254 {
255   info->mask = NO_ATTRIBUTE_MASK;
256   info->attributes = g_array_new (FALSE, FALSE,
257                                   sizeof (GFileAttribute));
258 }
259
260 /**
261  * g_file_info_new:
262  * 
263  * Creates a new file info structure.
264  * 
265  * Returns: a #GFileInfo.
266  **/
267 GFileInfo *
268 g_file_info_new (void)
269 {
270   return g_object_new (G_TYPE_FILE_INFO, NULL);
271 }
272
273 /**
274  * g_file_info_copy_into:
275  * @src_info: source to copy attributes from.
276  * @dest_info: destination to copy attributes to.
277  * 
278  * Copies all of the #GFileAttribute<!-- -->s from @src_info to @dest_info.
279  **/
280 void
281 g_file_info_copy_into (GFileInfo *src_info, 
282                        GFileInfo *dest_info)
283 {
284   GFileAttribute *source, *dest;
285   int i;
286
287   g_return_if_fail (G_IS_FILE_INFO (src_info));
288   g_return_if_fail (G_IS_FILE_INFO (dest_info));
289
290   dest = (GFileAttribute *)dest_info->attributes->data;
291   for (i = 0; i < dest_info->attributes->len; i++)
292     _g_file_attribute_value_clear (&dest[i].value);
293   
294   g_array_set_size (dest_info->attributes,
295                     src_info->attributes->len);
296
297   source = (GFileAttribute *)src_info->attributes->data;
298   dest = (GFileAttribute *)dest_info->attributes->data;
299   
300   for (i = 0; i < src_info->attributes->len; i++)
301     {
302       dest[i].attribute = source[i].attribute;
303       dest[i].value.type = G_FILE_ATTRIBUTE_TYPE_INVALID;
304       _g_file_attribute_value_set (&dest[i].value, &source[i].value);
305     }
306
307   if (dest_info->mask != NO_ATTRIBUTE_MASK)
308     g_file_attribute_matcher_unref (dest_info->mask);
309
310   if (src_info->mask == NO_ATTRIBUTE_MASK)
311     dest_info->mask = NO_ATTRIBUTE_MASK;
312   else
313     dest_info->mask = g_file_attribute_matcher_ref (src_info->mask);
314 }
315
316 /**
317  * g_file_info_dup:
318  * @other: a #GFileInfo.
319  * 
320  * Duplicates a file info structure.
321  * 
322  * Returns: a duplicate #GFileInfo of @other.
323  **/
324 GFileInfo *
325 g_file_info_dup (GFileInfo *other)
326 {
327   GFileInfo *new;
328   
329   g_return_val_if_fail (G_IS_FILE_INFO (other), NULL);
330   
331   new = g_file_info_new ();
332   g_file_info_copy_into (other, new);
333   return new;
334 }
335
336 /**
337  * g_file_info_set_attribute_mask:
338  * @info: a #GFileInfo.
339  * @mask: a #GFileAttributeMatcher.
340  *
341  * Sets @mask on @info to match specific attribute types.
342  **/
343 void
344 g_file_info_set_attribute_mask (GFileInfo             *info,
345                                 GFileAttributeMatcher *mask)
346 {
347   GFileAttribute *attr;
348   int i;
349   
350   g_return_if_fail (G_IS_FILE_INFO (info));
351   
352   if (mask != info->mask)
353     {
354       if (info->mask != NO_ATTRIBUTE_MASK)
355         g_file_attribute_matcher_unref (info->mask);
356       info->mask = g_file_attribute_matcher_ref (mask);
357
358       /* Remove non-matching attributes */
359       for (i = 0; i < info->attributes->len; i++)
360         {
361           attr = &g_array_index (info->attributes, GFileAttribute, i);
362           if (!g_file_attribute_matcher_matches_id (mask,
363                                                     attr->attribute))
364             {
365               _g_file_attribute_value_clear (&attr->value);
366               g_array_remove_index (info->attributes, i);
367               i--;
368             }
369         }
370     }
371 }
372
373 /**
374  * g_file_info_unset_attribute_mask:
375  * @info: #GFileInfo.
376  * 
377  * Unsets a mask set by g_file_info_set_attribute_mask(), if one
378  * is set.
379  **/
380 void
381 g_file_info_unset_attribute_mask (GFileInfo *info)
382 {
383   g_return_if_fail (G_IS_FILE_INFO (info));
384
385   if (info->mask != NO_ATTRIBUTE_MASK)
386     g_file_attribute_matcher_unref (info->mask);
387   info->mask = NO_ATTRIBUTE_MASK;
388 }
389
390 /**
391  * g_file_info_clear_status:
392  * @info: a #GFileInfo.
393  *
394  * Clears the status information from @info.
395  **/
396 void
397 g_file_info_clear_status (GFileInfo  *info)
398 {
399   GFileAttribute *attrs;
400   int i;
401   
402   g_return_if_fail (G_IS_FILE_INFO (info));
403
404   attrs = (GFileAttribute *)info->attributes->data;
405   for (i = 0; i < info->attributes->len; i++)
406     attrs[i].value.status = G_FILE_ATTRIBUTE_STATUS_UNSET;
407 }
408
409 static int
410 g_file_info_find_place (GFileInfo  *info,
411                         guint32     attribute)
412 {
413   int min, max, med;
414   GFileAttribute *attrs;
415   /* Binary search for the place where attribute would be, if it's
416      in the array */
417
418   min = 0;
419   max = info->attributes->len;
420
421   attrs = (GFileAttribute *)info->attributes->data;
422
423   while (min < max)
424     {
425       med = min + (max - min) / 2;
426       if (attrs[med].attribute == attribute)
427         {
428           min = med;
429           break;
430         }
431       else if (attrs[med].attribute < attribute)
432         min = med + 1;
433       else /* attrs[med].attribute > attribute */
434         max = med;
435     }
436
437   return min;
438 }
439
440 static GFileAttributeValue *
441 g_file_info_find_value (GFileInfo *info,
442                         guint32    attr_id)
443 {
444   GFileAttribute *attrs;
445   int i;
446
447   i = g_file_info_find_place (info, attr_id);
448   attrs = (GFileAttribute *)info->attributes->data;
449   if (i < info->attributes->len &&
450       attrs[i].attribute == attr_id)
451     return &attrs[i].value;
452   
453   return NULL;
454 }
455
456 static GFileAttributeValue *
457 g_file_info_find_value_by_name (GFileInfo  *info,
458                                 const char *attribute)
459 {
460   guint32 attr_id;
461
462   attr_id = lookup_attribute (attribute);
463   return g_file_info_find_value (info, attr_id);
464 }
465
466 /**
467  * g_file_info_has_attribute:
468  * @info: a #GFileInfo.
469  * @attribute: a file attribute key.
470  * 
471  * Checks if a file info structure has an attribute named @attribute.
472  * 
473  * Returns: %TRUE if @Ginfo has an attribute named @attribute, 
474  *     %FALSE otherwise.
475  **/
476 gboolean
477 g_file_info_has_attribute (GFileInfo  *info,
478                            const char *attribute)
479 {
480   GFileAttributeValue *value;
481
482   g_return_val_if_fail (G_IS_FILE_INFO (info), FALSE);
483   g_return_val_if_fail (attribute != NULL && *attribute != '\0', FALSE);
484
485   value = g_file_info_find_value_by_name (info, attribute);
486   return value != NULL;
487 }
488
489 /**
490  * g_file_info_has_namespace:
491  * @info: a #GFileInfo.
492  * @name_space: a file attribute namespace.
493  *
494  * Checks if a file info structure has an attribute in the
495  * specified @name_space.
496  *
497  * Returns: %TRUE if @Ginfo has an attribute in @name_space,
498  *     %FALSE otherwise.
499  *
500  * Since: 2.22
501  **/
502 gboolean
503 g_file_info_has_namespace (GFileInfo  *info,
504                            const char *name_space)
505 {
506   GFileAttribute *attrs;
507   guint32 ns_id;
508   int i;
509
510   g_return_val_if_fail (G_IS_FILE_INFO (info), FALSE);
511   g_return_val_if_fail (name_space != NULL, FALSE);
512
513   ns_id = lookup_namespace (name_space);
514
515   attrs = (GFileAttribute *)info->attributes->data;
516   for (i = 0; i < info->attributes->len; i++)
517     {
518       if (GET_NS (attrs[i].attribute) == ns_id)
519         return TRUE;
520     }
521
522   return FALSE;
523 }
524
525 /**
526  * g_file_info_list_attributes:
527  * @info: a #GFileInfo.
528  * @name_space: a file attribute key's namespace.
529  * 
530  * Lists the file info structure's attributes.
531  * 
532  * Returns: a null-terminated array of strings of all of the 
533  * possible attribute types for the given @name_space, or 
534  * %NULL on error.
535  **/
536 char **
537 g_file_info_list_attributes (GFileInfo  *info,
538                              const char *name_space)
539 {
540   GPtrArray *names;
541   GFileAttribute *attrs;
542   guint32 attribute;
543   guint32 ns_id = (name_space) ? lookup_namespace (name_space) : 0;
544   int i;
545  
546   g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
547
548   names = g_ptr_array_new ();
549   attrs = (GFileAttribute *)info->attributes->data;
550   for (i = 0; i < info->attributes->len; i++)
551     {
552       attribute = attrs[i].attribute;
553       if (ns_id == 0 || GET_NS (attribute) == ns_id)
554         g_ptr_array_add (names, g_strdup (get_attribute_for_id (attribute)));
555     }
556
557   /* NULL terminate */
558   g_ptr_array_add (names, NULL);
559   
560   return (char **)g_ptr_array_free (names, FALSE);
561 }
562
563 /**
564  * g_file_info_get_attribute_type:
565  * @info: a #GFileInfo.
566  * @attribute: a file attribute key.
567  * 
568  * Gets the attribute type for an attribute key.
569  * 
570  * Returns: a #GFileAttributeType for the given @attribute, or 
571  * %G_FILE_ATTRIBUTE_TYPE_INVALID if the key is not set.
572  **/
573 GFileAttributeType
574 g_file_info_get_attribute_type (GFileInfo  *info,
575                                 const char *attribute)
576 {
577   GFileAttributeValue *value;
578   
579   g_return_val_if_fail (G_IS_FILE_INFO (info), G_FILE_ATTRIBUTE_TYPE_INVALID);
580   g_return_val_if_fail (attribute != NULL && *attribute != '\0', G_FILE_ATTRIBUTE_TYPE_INVALID);
581
582   value = g_file_info_find_value_by_name (info, attribute);
583   if (value)
584     return value->type;
585   else
586     return G_FILE_ATTRIBUTE_TYPE_INVALID;
587 }
588
589 /**
590  * g_file_info_remove_attribute:
591  * @info: a #GFileInfo.
592  * @attribute: a file attribute key.
593  * 
594  * Removes all cases of @attribute from @info if it exists.
595  **/
596 void
597 g_file_info_remove_attribute (GFileInfo  *info,
598                               const char *attribute)
599 {
600   guint32 attr_id;
601   GFileAttribute *attrs;
602   int i;
603
604   g_return_if_fail (G_IS_FILE_INFO (info));
605   g_return_if_fail (attribute != NULL && *attribute != '\0');
606
607   attr_id = lookup_attribute (attribute);
608   
609   i = g_file_info_find_place (info, attr_id);
610   attrs = (GFileAttribute *)info->attributes->data;
611   if (i < info->attributes->len &&
612       attrs[i].attribute == attr_id)
613     {
614       _g_file_attribute_value_clear (&attrs[i].value);
615       g_array_remove_index (info->attributes, i);
616     }
617 }
618
619 /**
620  * g_file_info_get_attribute_data:
621  * @info: a #GFileInfo
622  * @attribute: a file attribute key
623  * @type: return location for the attribute type, or %NULL
624  * @value_pp: return location for the attribute value, or %NULL
625  * @status: return location for the attribute status, or %NULL
626  *
627  * Gets the attribute type, value and status for an attribute key.
628  *
629  * Returns: %TRUE if @info has an attribute named @attribute, 
630  *      %FALSE otherwise.
631  */
632 gboolean
633 g_file_info_get_attribute_data (GFileInfo            *info,
634                                 const char           *attribute,
635                                 GFileAttributeType   *type,
636                                 gpointer             *value_pp,
637                                 GFileAttributeStatus *status)
638 {
639   GFileAttributeValue *value;
640
641   value = g_file_info_find_value_by_name (info, attribute);
642   if (value == NULL)
643     return FALSE;
644
645   if (status)
646     *status = value->status;
647
648   if (type)
649     *type = value->type;
650
651   if (value_pp)
652     *value_pp = _g_file_attribute_value_peek_as_pointer (value);
653   
654   return TRUE;
655 }
656
657 /** 
658  * g_file_info_get_attribute_status:
659  * @info: a #GFileInfo
660  * @attribute: a file attribute key
661  *
662  * Gets the attribute status for an attribute key.
663  *
664  * Returns: a #GFileAttributeStatus for the given @attribute, or 
665  *    %G_FILE_ATTRIBUTE_STATUS_UNSET if the key is invalid.
666  *
667  */
668 GFileAttributeStatus
669 g_file_info_get_attribute_status (GFileInfo  *info,
670                                   const char *attribute)
671 {
672   GFileAttributeValue *val;
673   
674   g_return_val_if_fail (G_IS_FILE_INFO (info), 0);
675   g_return_val_if_fail (attribute != NULL && *attribute != '\0', 0);
676
677   val = g_file_info_find_value_by_name (info, attribute);
678   if (val)
679     return val->status;
680
681   return G_FILE_ATTRIBUTE_STATUS_UNSET;
682 }
683
684 /**
685  * g_file_info_set_attribute_status:
686  * @info: a #GFileInfo
687  * @attribute: a file attribute key
688  * @status: a #GFileAttributeStatus
689  *
690  * Sets the attribute status for an attribute key. This is only
691  * needed by external code that implement g_file_set_attributes_from_info()
692  * or similar functions.
693  *
694  * The attribute must exist in @info for this to work. Otherwise %FALSE
695  * is returned and @info is unchanged.
696  *
697  * Returns: %TRUE if the status was changed, %FALSE if the key was not set.
698  *
699  * Since: 2.22
700  */
701 gboolean
702 g_file_info_set_attribute_status (GFileInfo  *info,
703                                   const char *attribute,
704                                   GFileAttributeStatus status)
705 {
706   GFileAttributeValue *val;
707
708   g_return_val_if_fail (G_IS_FILE_INFO (info), 0);
709   g_return_val_if_fail (attribute != NULL && *attribute != '\0', 0);
710
711   val = g_file_info_find_value_by_name (info, attribute);
712   if (val)
713     {
714       val->status = status;
715       return TRUE;
716     }
717
718   return FALSE;
719 }
720
721 GFileAttributeValue *
722 _g_file_info_get_attribute_value (GFileInfo  *info,
723                                   const char *attribute)
724   
725 {
726   g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
727   g_return_val_if_fail (attribute != NULL && *attribute != '\0', NULL);
728
729   return g_file_info_find_value_by_name (info, attribute);
730 }
731
732 /**
733  * g_file_info_get_attribute_as_string:
734  * @info: a #GFileInfo.
735  * @attribute: a file attribute key.
736  * 
737  * Gets the value of a attribute, formated as a string.
738  * This escapes things as needed to make the string valid
739  * utf8.
740  * 
741  * Returns: a UTF-8 string associated with the given @attribute.
742  *    When you're done with the string it must be freed with g_free().
743  **/
744 char *
745 g_file_info_get_attribute_as_string (GFileInfo  *info,
746                                      const char *attribute)
747 {
748   GFileAttributeValue *val;
749   val = _g_file_info_get_attribute_value (info, attribute);
750   if (val) 
751     return _g_file_attribute_value_as_string (val);
752   return NULL;
753 }
754
755
756 /**
757  * g_file_info_get_attribute_object:
758  * @info: a #GFileInfo.
759  * @attribute: a file attribute key.
760  * 
761  * Gets the value of a #GObject attribute. If the attribute does 
762  * not contain a #GObject, %NULL will be returned.
763  * 
764  * Returns: a #GObject associated with the given @attribute, or
765  * %NULL otherwise.
766  **/
767 GObject *
768 g_file_info_get_attribute_object (GFileInfo  *info,
769                                   const char *attribute)
770 {
771   GFileAttributeValue *value;
772   
773   g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
774   g_return_val_if_fail (attribute != NULL && *attribute != '\0', NULL);
775
776   value = g_file_info_find_value_by_name (info, attribute);
777   return _g_file_attribute_value_get_object (value);
778 }
779
780 /**
781  * g_file_info_get_attribute_string:
782  * @info: a #GFileInfo.
783  * @attribute: a file attribute key.
784  * 
785  * Gets the value of a string attribute. If the attribute does 
786  * not contain a string, %NULL will be returned.
787  * 
788  * Returns: the contents of the @attribute value as a string, or 
789  * %NULL otherwise.
790  **/
791 const char *
792 g_file_info_get_attribute_string (GFileInfo  *info,
793                                   const char *attribute)
794 {
795   GFileAttributeValue *value;
796   
797   g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
798   g_return_val_if_fail (attribute != NULL && *attribute != '\0', NULL);
799
800   value = g_file_info_find_value_by_name (info, attribute);
801   return _g_file_attribute_value_get_string (value);
802 }
803
804 /**
805  * g_file_info_get_attribute_byte_string:
806  * @info: a #GFileInfo.
807  * @attribute: a file attribute key.
808  * 
809  * Gets the value of a byte string attribute. If the attribute does 
810  * not contain a byte string, %NULL will be returned.
811  * 
812  * Returns: the contents of the @attribute value as a byte string, or 
813  * %NULL otherwise.
814  **/
815 const char *
816 g_file_info_get_attribute_byte_string (GFileInfo  *info,
817                                        const char *attribute)
818 {
819   GFileAttributeValue *value;
820   
821   g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
822   g_return_val_if_fail (attribute != NULL && *attribute != '\0', NULL);
823
824   value = g_file_info_find_value_by_name (info, attribute);
825   return _g_file_attribute_value_get_byte_string (value);
826 }
827
828 /**
829  * g_file_info_get_attribute_stringv:
830  * @info: a #GFileInfo.
831  * @attribute: a file attribute key.
832  *
833  * Gets the value of a stringv attribute. If the attribute does
834  * not contain a stringv, %NULL will be returned.
835  *
836  * Returns: the contents of the @attribute value as a stringv, or
837  * %NULL otherwise. Do not free.
838  **/
839 char **
840 g_file_info_get_attribute_stringv (GFileInfo  *info,
841                                    const char *attribute)
842 {
843   GFileAttributeValue *value;
844
845   g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
846   g_return_val_if_fail (attribute != NULL && *attribute != '\0', NULL);
847
848   value = g_file_info_find_value_by_name (info, attribute);
849   return _g_file_attribute_value_get_stringv (value);
850 }
851
852 /**
853  * g_file_info_get_attribute_boolean:
854  * @info: a #GFileInfo.
855  * @attribute: a file attribute key.
856  * 
857  * Gets the value of a boolean attribute. If the attribute does not
858  * contain a boolean value, %FALSE will be returned.
859  * 
860  * Returns: the boolean value contained within the attribute. 
861  **/
862 gboolean
863 g_file_info_get_attribute_boolean (GFileInfo  *info,
864                                    const char *attribute)
865 {
866   GFileAttributeValue *value;
867   
868   g_return_val_if_fail (G_IS_FILE_INFO (info), FALSE);
869   g_return_val_if_fail (attribute != NULL && *attribute != '\0', FALSE);
870
871   value = g_file_info_find_value_by_name (info, attribute);
872   return _g_file_attribute_value_get_boolean (value);
873 }
874
875 /**
876  * g_file_info_get_attribute_uint32:
877  * @info: a #GFileInfo.
878  * @attribute: a file attribute key.
879  * 
880  * Gets an unsigned 32-bit integer contained within the attribute. If the 
881  * attribute does not contain an unsigned 32-bit integer, or is invalid, 
882  * 0 will be returned.
883  * 
884  * Returns: an unsigned 32-bit integer from the attribute. 
885  **/
886 guint32
887 g_file_info_get_attribute_uint32 (GFileInfo  *info,
888                                   const char *attribute)
889 {
890   GFileAttributeValue *value;
891   
892   g_return_val_if_fail (G_IS_FILE_INFO (info), 0);
893   g_return_val_if_fail (attribute != NULL && *attribute != '\0', 0);
894
895   value = g_file_info_find_value_by_name (info, attribute);
896   return _g_file_attribute_value_get_uint32 (value);
897 }
898
899 /**
900  * g_file_info_get_attribute_int32:
901  * @info: a #GFileInfo.
902  * @attribute: a file attribute key.
903  * 
904  * Gets a signed 32-bit integer contained within the attribute. If the 
905  * attribute does not contain a signed 32-bit integer, or is invalid, 
906  * 0 will be returned.
907  * 
908  * Returns: a signed 32-bit integer from the attribute.
909  **/
910 gint32
911 g_file_info_get_attribute_int32 (GFileInfo  *info,
912                                  const char *attribute)
913 {
914   GFileAttributeValue *value;
915
916   g_return_val_if_fail (G_IS_FILE_INFO (info), 0);
917   g_return_val_if_fail (attribute != NULL && *attribute != '\0', 0);
918
919   value = g_file_info_find_value_by_name (info, attribute);
920   return _g_file_attribute_value_get_int32 (value);
921 }
922
923 /**
924  * g_file_info_get_attribute_uint64:
925  * @info: a #GFileInfo.
926  * @attribute: a file attribute key.
927  * 
928  * Gets a unsigned 64-bit integer contained within the attribute. If the 
929  * attribute does not contain an unsigned 64-bit integer, or is invalid, 
930  * 0 will be returned.
931  * 
932  * Returns: a unsigned 64-bit integer from the attribute. 
933  **/
934 guint64
935 g_file_info_get_attribute_uint64 (GFileInfo  *info,
936                                   const char *attribute)
937 {
938   GFileAttributeValue *value;
939
940   g_return_val_if_fail (G_IS_FILE_INFO (info), 0);
941   g_return_val_if_fail (attribute != NULL && *attribute != '\0', 0);
942
943   value = g_file_info_find_value_by_name (info, attribute);
944   return _g_file_attribute_value_get_uint64 (value);
945 }
946
947 /**
948  * g_file_info_get_attribute_int64:
949  * @info: a #GFileInfo.
950  * @attribute: a file attribute key.
951  * 
952  * Gets a signed 64-bit integer contained within the attribute. If the 
953  * attribute does not contain an signed 64-bit integer, or is invalid, 
954  * 0 will be returned.
955  * 
956  * Returns: a signed 64-bit integer from the attribute. 
957  **/
958 gint64
959 g_file_info_get_attribute_int64  (GFileInfo  *info,
960                                   const char *attribute)
961 {
962   GFileAttributeValue *value;
963
964   g_return_val_if_fail (G_IS_FILE_INFO (info), 0);
965   g_return_val_if_fail (attribute != NULL && *attribute != '\0', 0);
966
967   value = g_file_info_find_value_by_name (info, attribute);
968   return _g_file_attribute_value_get_int64 (value);
969 }
970
971 static GFileAttributeValue *
972 g_file_info_create_value (GFileInfo *info,
973                           guint32 attr_id)
974 {
975   GFileAttribute *attrs;
976   int i;
977
978   if (info->mask != NO_ATTRIBUTE_MASK &&
979       !g_file_attribute_matcher_matches_id (info->mask, attr_id))
980     return NULL;
981   
982   i = g_file_info_find_place (info, attr_id);
983   
984   attrs = (GFileAttribute *)info->attributes->data;
985   if (i < info->attributes->len &&
986       attrs[i].attribute == attr_id)
987     return &attrs[i].value;
988   else
989     {
990       GFileAttribute attr = { 0 };
991       attr.attribute = attr_id;
992       g_array_insert_val (info->attributes, i, attr);
993
994       attrs = (GFileAttribute *)info->attributes->data;
995       return &attrs[i].value;
996     }
997 }
998
999 static GFileAttributeValue *
1000 g_file_info_create_value_by_name (GFileInfo *info,
1001                                   const char *attribute)
1002 {
1003   guint32 attr_id;
1004
1005   attr_id = lookup_attribute (attribute);
1006
1007   return g_file_info_create_value (info, attr_id);
1008 }
1009
1010 /**
1011  * g_file_info_set_attribute:
1012  * @info: a #GFileInfo.
1013  * @attribute: a file attribute key.
1014  * @type: a #GFileAttributeType
1015  * @value_p: pointer to the value
1016  * 
1017  * Sets the @attribute to contain the given value, if possible.
1018  **/
1019 void
1020 g_file_info_set_attribute (GFileInfo                 *info,
1021                            const char                *attribute,
1022                            GFileAttributeType         type,
1023                            gpointer                   value_p)
1024 {
1025   GFileAttributeValue *value;
1026
1027   g_return_if_fail (G_IS_FILE_INFO (info));
1028   g_return_if_fail (attribute != NULL && *attribute != '\0');
1029
1030   value = g_file_info_create_value_by_name (info, attribute);
1031
1032   if (value)
1033     _g_file_attribute_value_set_from_pointer (value, type, value_p, TRUE);
1034 }
1035
1036 /**
1037  * g_file_info_set_attribute_object:
1038  * @info: a #GFileInfo.
1039  * @attribute: a file attribute key.
1040  * @attr_value: a #GObject.
1041  * 
1042  * Sets the @attribute to contain the given @attr_value, 
1043  * if possible.
1044  **/
1045 void
1046 g_file_info_set_attribute_object (GFileInfo  *info,
1047                                   const char *attribute,
1048                                   GObject    *attr_value)
1049 {
1050   GFileAttributeValue *value;
1051
1052   g_return_if_fail (G_IS_FILE_INFO (info));
1053   g_return_if_fail (attribute != NULL && *attribute != '\0');
1054   g_return_if_fail (G_IS_OBJECT (attr_value));
1055
1056   value = g_file_info_create_value_by_name (info, attribute);
1057   if (value)
1058     _g_file_attribute_value_set_object (value, attr_value);
1059 }
1060
1061 /**
1062  * g_file_info_set_attribute_stringv:
1063  * @info: a #GFileInfo.
1064  * @attribute: a file attribute key.
1065  * @attr_value: a %NULL terminated string array
1066  *
1067  * Sets the @attribute to contain the given @attr_value,
1068  * if possible.
1069  *
1070  * Sinze: 2.22
1071  **/
1072 void
1073 g_file_info_set_attribute_stringv (GFileInfo  *info,
1074                                    const char *attribute,
1075                                    char      **attr_value)
1076 {
1077   GFileAttributeValue *value;
1078
1079   g_return_if_fail (G_IS_FILE_INFO (info));
1080   g_return_if_fail (attribute != NULL && *attribute != '\0');
1081   g_return_if_fail (attr_value != NULL);
1082
1083   value = g_file_info_create_value_by_name (info, attribute);
1084   if (value)
1085     _g_file_attribute_value_set_stringv (value, attr_value);
1086 }
1087
1088 /**
1089  * g_file_info_set_attribute_string:
1090  * @info: a #GFileInfo.
1091  * @attribute: a file attribute key.
1092  * @attr_value: a string.
1093  * 
1094  * Sets the @attribute to contain the given @attr_value, 
1095  * if possible.
1096  **/
1097 void
1098 g_file_info_set_attribute_string (GFileInfo  *info,
1099                                   const char *attribute,
1100                                   const char *attr_value)
1101 {
1102   GFileAttributeValue *value;
1103   
1104   g_return_if_fail (G_IS_FILE_INFO (info));
1105   g_return_if_fail (attribute != NULL && *attribute != '\0');
1106   g_return_if_fail (attr_value != NULL);
1107
1108   value = g_file_info_create_value_by_name (info, attribute);
1109   if (value)
1110     _g_file_attribute_value_set_string (value, attr_value);
1111 }
1112
1113 /**
1114  * g_file_info_set_attribute_byte_string:
1115  * @info: a #GFileInfo.
1116  * @attribute: a file attribute key.
1117  * @attr_value: a byte string.
1118  * 
1119  * Sets the @attribute to contain the given @attr_value, 
1120  * if possible.
1121  **/
1122 void
1123 g_file_info_set_attribute_byte_string (GFileInfo  *info,
1124                                        const char *attribute,
1125                                        const char *attr_value)
1126 {
1127   GFileAttributeValue *value;
1128
1129   g_return_if_fail (G_IS_FILE_INFO (info));
1130   g_return_if_fail (attribute != NULL && *attribute != '\0');
1131   g_return_if_fail (attr_value != NULL);
1132
1133   value = g_file_info_create_value_by_name (info, attribute);
1134   if (value)
1135     _g_file_attribute_value_set_byte_string (value, attr_value);
1136 }
1137
1138 /**
1139  * g_file_info_set_attribute_boolean:
1140  * @info: a #GFileInfo.
1141  * @attribute: a file attribute key.
1142  * @attr_value: a boolean value.
1143  * 
1144  * Sets the @attribute to contain the given @attr_value, 
1145  * if possible.
1146  **/
1147 void
1148 g_file_info_set_attribute_boolean (GFileInfo  *info,
1149                                    const char *attribute,
1150                                    gboolean    attr_value)
1151 {
1152   GFileAttributeValue *value;
1153
1154   g_return_if_fail (G_IS_FILE_INFO (info));
1155   g_return_if_fail (attribute != NULL && *attribute != '\0');
1156
1157   value = g_file_info_create_value_by_name (info, attribute);
1158   if (value)
1159     _g_file_attribute_value_set_boolean (value, attr_value);
1160 }
1161
1162 /**
1163  * g_file_info_set_attribute_uint32:
1164  * @info: a #GFileInfo.
1165  * @attribute: a file attribute key.
1166  * @attr_value: an unsigned 32-bit integer.
1167  * 
1168  * Sets the @attribute to contain the given @attr_value, 
1169  * if possible.
1170  **/
1171 void
1172 g_file_info_set_attribute_uint32 (GFileInfo  *info,
1173                                   const char *attribute,
1174                                   guint32     attr_value)
1175 {
1176   GFileAttributeValue *value;
1177
1178   g_return_if_fail (G_IS_FILE_INFO (info));
1179   g_return_if_fail (attribute != NULL && *attribute != '\0');
1180
1181   value = g_file_info_create_value_by_name (info, attribute);
1182   if (value)
1183     _g_file_attribute_value_set_uint32 (value, attr_value);
1184 }
1185
1186
1187 /**
1188  * g_file_info_set_attribute_int32:
1189  * @info: a #GFileInfo.
1190  * @attribute: a file attribute key.
1191  * @attr_value: a signed 32-bit integer
1192  * 
1193  * Sets the @attribute to contain the given @attr_value, 
1194  * if possible.
1195  **/
1196 void
1197 g_file_info_set_attribute_int32 (GFileInfo  *info,
1198                                  const char *attribute,
1199                                  gint32      attr_value)
1200 {
1201   GFileAttributeValue *value;
1202  
1203   g_return_if_fail (G_IS_FILE_INFO (info));
1204   g_return_if_fail (attribute != NULL && *attribute != '\0');
1205
1206   value = g_file_info_create_value_by_name (info, attribute);
1207   if (value)
1208     _g_file_attribute_value_set_int32 (value, attr_value);
1209 }
1210
1211 /**
1212  * g_file_info_set_attribute_uint64:
1213  * @info: a #GFileInfo.
1214  * @attribute: a file attribute key.
1215  * @attr_value: an unsigned 64-bit integer.
1216  * 
1217  * Sets the @attribute to contain the given @attr_value, 
1218  * if possible.
1219  **/
1220 void
1221 g_file_info_set_attribute_uint64 (GFileInfo  *info,
1222                                   const char *attribute,
1223                                   guint64     attr_value)
1224 {
1225   GFileAttributeValue *value;
1226
1227   g_return_if_fail (G_IS_FILE_INFO (info));
1228   g_return_if_fail (attribute != NULL && *attribute != '\0');
1229
1230   value = g_file_info_create_value_by_name (info, attribute);
1231   if (value)
1232     _g_file_attribute_value_set_uint64 (value, attr_value);
1233 }
1234
1235 /**
1236  * g_file_info_set_attribute_int64:
1237  * @info: a #GFileInfo.
1238  * @attribute: attribute name to set.
1239  * @attr_value: int64 value to set attribute to.
1240  * 
1241  * Sets the @attribute to contain the given @attr_value, 
1242  * if possible.
1243  * 
1244  **/
1245 void
1246 g_file_info_set_attribute_int64  (GFileInfo  *info,
1247                                   const char *attribute,
1248                                   gint64      attr_value)
1249 {
1250   GFileAttributeValue *value;
1251
1252   g_return_if_fail (G_IS_FILE_INFO (info));
1253   g_return_if_fail (attribute != NULL && *attribute != '\0');
1254
1255   value = g_file_info_create_value_by_name (info, attribute);
1256   if (value)
1257     _g_file_attribute_value_set_int64 (value, attr_value);
1258 }
1259
1260 /* Helper getters */
1261 /**
1262  * g_file_info_get_file_type:
1263  * @info: a #GFileInfo.
1264  * 
1265  * Gets a file's type (whether it is a regular file, symlink, etc). 
1266  * This is different from the file's content type, see g_file_info_get_content_type().
1267  * 
1268  * Returns: a #GFileType for the given file.
1269  **/
1270 GFileType
1271 g_file_info_get_file_type (GFileInfo *info)
1272 {
1273   static guint32 attr = 0;
1274   GFileAttributeValue *value;
1275
1276   g_return_val_if_fail (G_IS_FILE_INFO (info), G_FILE_TYPE_UNKNOWN);
1277   
1278   if (attr == 0)
1279     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_TYPE);
1280   
1281   value = g_file_info_find_value (info, attr);
1282   return (GFileType)_g_file_attribute_value_get_uint32 (value);
1283 }
1284
1285 /**
1286  * g_file_info_get_is_hidden:
1287  * @info: a #GFileInfo.
1288  * 
1289  * Checks if a file is hidden.
1290  * 
1291  * Returns: %TRUE if the file is a hidden file, %FALSE otherwise.
1292  **/
1293 gboolean
1294 g_file_info_get_is_hidden (GFileInfo *info)
1295 {
1296   static guint32 attr = 0;
1297   GFileAttributeValue *value;
1298   
1299   g_return_val_if_fail (G_IS_FILE_INFO (info), FALSE);
1300   
1301   if (attr == 0)
1302     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN);
1303   
1304   value = g_file_info_find_value (info, attr);
1305   return (GFileType)_g_file_attribute_value_get_boolean (value);
1306 }
1307
1308 /**
1309  * g_file_info_get_is_backup:
1310  * @info: a #GFileInfo.
1311  * 
1312  * Checks if a file is a backup file.
1313  * 
1314  * Returns: %TRUE if file is a backup file, %FALSE otherwise.
1315  **/
1316 gboolean
1317 g_file_info_get_is_backup (GFileInfo *info)
1318 {
1319   static guint32 attr = 0;
1320   GFileAttributeValue *value;
1321   
1322   g_return_val_if_fail (G_IS_FILE_INFO (info), FALSE);
1323   
1324   if (attr == 0)
1325     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_IS_BACKUP);
1326   
1327   value = g_file_info_find_value (info, attr);
1328   return (GFileType)_g_file_attribute_value_get_boolean (value);
1329 }
1330
1331 /**
1332  * g_file_info_get_is_symlink:
1333  * @info: a #GFileInfo.
1334  * 
1335  * Checks if a file is a symlink.
1336  * 
1337  * Returns: %TRUE if the given @info is a symlink.
1338  **/
1339 gboolean
1340 g_file_info_get_is_symlink (GFileInfo *info)
1341 {
1342   static guint32 attr = 0;
1343   GFileAttributeValue *value;
1344   
1345   g_return_val_if_fail (G_IS_FILE_INFO (info), FALSE);
1346   
1347   if (attr == 0)
1348     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK);
1349   
1350   value = g_file_info_find_value (info, attr);
1351   return (GFileType)_g_file_attribute_value_get_boolean (value);
1352 }
1353
1354 /**
1355  * g_file_info_get_name:
1356  * @info: a #GFileInfo.
1357  * 
1358  * Gets the name for a file.
1359  * 
1360  * Returns: a string containing the file name.
1361  **/
1362 const char *
1363 g_file_info_get_name (GFileInfo *info)
1364 {
1365   static guint32 attr = 0;
1366   GFileAttributeValue *value;
1367   
1368   g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
1369   
1370   if (attr == 0)
1371     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_NAME);
1372   
1373   value = g_file_info_find_value (info, attr);
1374   return _g_file_attribute_value_get_byte_string (value);
1375 }
1376
1377 /**
1378  * g_file_info_get_display_name:
1379  * @info: a #GFileInfo.
1380  * 
1381  * Gets a display name for a file.
1382  * 
1383  * Returns: a string containing the display name.
1384  **/
1385 const char *
1386 g_file_info_get_display_name (GFileInfo *info)
1387 {
1388   static guint32 attr = 0;
1389   GFileAttributeValue *value;
1390   
1391   g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
1392   
1393   if (attr == 0)
1394     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME);
1395   
1396   value = g_file_info_find_value (info, attr);
1397   return _g_file_attribute_value_get_string (value);
1398 }
1399
1400 /**
1401  * g_file_info_get_edit_name:
1402  * @info: a #GFileInfo.
1403  * 
1404  * Gets the edit name for a file.
1405  * 
1406  * Returns: a string containing the edit name.
1407  **/
1408 const char *
1409 g_file_info_get_edit_name (GFileInfo *info)
1410 {
1411   static guint32 attr = 0;
1412   GFileAttributeValue *value;
1413   
1414   g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
1415   
1416   if (attr == 0)
1417     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_EDIT_NAME);
1418   
1419   value = g_file_info_find_value (info, attr);
1420   return _g_file_attribute_value_get_string (value);
1421 }
1422
1423 /**
1424  * g_file_info_get_icon:
1425  * @info: a #GFileInfo.
1426  * 
1427  * Gets the icon for a file.
1428  * 
1429  * Returns: #GIcon for the given @info.
1430  **/
1431 GIcon *
1432 g_file_info_get_icon (GFileInfo *info)
1433 {
1434   static guint32 attr = 0;
1435   GFileAttributeValue *value;
1436   GObject *obj;
1437   
1438   g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
1439   
1440   if (attr == 0)
1441     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_ICON);
1442   
1443   value = g_file_info_find_value (info, attr);
1444   obj = _g_file_attribute_value_get_object (value);
1445   if (G_IS_ICON (obj))
1446     return G_ICON (obj);
1447   return NULL;
1448 }
1449
1450 /**
1451  * g_file_info_get_content_type:
1452  * @info: a #GFileInfo.
1453  * 
1454  * Gets the file's content type.
1455  * 
1456  * Returns: a string containing the file's content type.
1457  **/
1458 const char *
1459 g_file_info_get_content_type (GFileInfo *info)
1460 {
1461   static guint32 attr = 0;
1462   GFileAttributeValue *value;
1463   
1464   g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
1465   
1466   if (attr == 0)
1467     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE);
1468   
1469   value = g_file_info_find_value (info, attr);
1470   return _g_file_attribute_value_get_string (value);
1471 }
1472
1473 /**
1474  * g_file_info_get_size:
1475  * @info: a #GFileInfo.
1476  * 
1477  * Gets the file's size.
1478  * 
1479  * Returns: a #goffset containing the file's size. 
1480  **/
1481 goffset
1482 g_file_info_get_size (GFileInfo *info)
1483 {
1484   static guint32 attr = 0;
1485   GFileAttributeValue *value;
1486  
1487   g_return_val_if_fail (G_IS_FILE_INFO (info), (goffset) 0);
1488   
1489   if (attr == 0)
1490     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_SIZE);
1491   
1492   value = g_file_info_find_value (info, attr);
1493   return (goffset) _g_file_attribute_value_get_uint64 (value);
1494 }
1495
1496 /**
1497  * g_file_info_get_modification_time:
1498  * @info: a #GFileInfo.
1499  * @result: a #GTimeVal.
1500  * 
1501  * Gets the modification time of the current @info and sets it
1502  * in @result.
1503  **/
1504 void
1505 g_file_info_get_modification_time (GFileInfo *info,
1506                                    GTimeVal  *result)
1507 {
1508   static guint32 attr_mtime = 0, attr_mtime_usec;
1509   GFileAttributeValue *value;
1510
1511   g_return_if_fail (G_IS_FILE_INFO (info));
1512   g_return_if_fail (result != NULL);
1513   
1514   if (attr_mtime == 0)
1515     {
1516       attr_mtime = lookup_attribute (G_FILE_ATTRIBUTE_TIME_MODIFIED);
1517       attr_mtime_usec = lookup_attribute (G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC);
1518     }
1519   
1520   value = g_file_info_find_value (info, attr_mtime);
1521   result->tv_sec = _g_file_attribute_value_get_uint64 (value);
1522   value = g_file_info_find_value (info, attr_mtime_usec);
1523   result->tv_usec = _g_file_attribute_value_get_uint32 (value);
1524 }
1525
1526 /**
1527  * g_file_info_get_symlink_target:
1528  * @info: a #GFileInfo.
1529  * 
1530  * Gets the symlink target for a given #GFileInfo.
1531  * 
1532  * Returns: a string containing the symlink target.
1533  **/
1534 const char *
1535 g_file_info_get_symlink_target (GFileInfo *info)
1536 {
1537   static guint32 attr = 0;
1538   GFileAttributeValue *value;
1539   
1540   g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
1541   
1542   if (attr == 0)
1543     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET);
1544   
1545   value = g_file_info_find_value (info, attr);
1546   return _g_file_attribute_value_get_byte_string (value);
1547 }
1548
1549 /**
1550  * g_file_info_get_etag:
1551  * @info: a #GFileInfo.
1552  * 
1553  * Gets the <link linkend="gfile-etag">entity tag</link> for a given 
1554  * #GFileInfo. See %G_FILE_ATTRIBUTE_ETAG_VALUE.
1555  * 
1556  * Returns: a string containing the value of the "etag:value" attribute.
1557  **/
1558 const char *
1559 g_file_info_get_etag (GFileInfo *info)
1560 {
1561   static guint32 attr = 0;
1562   GFileAttributeValue *value;
1563   
1564   g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
1565   
1566   if (attr == 0)
1567     attr = lookup_attribute (G_FILE_ATTRIBUTE_ETAG_VALUE);
1568   
1569   value = g_file_info_find_value (info, attr);
1570   return _g_file_attribute_value_get_string (value);
1571 }
1572
1573 /**
1574  * g_file_info_get_sort_order:
1575  * @info: a #GFileInfo.
1576  * 
1577  * Gets the value of the sort_order attribute from the #GFileInfo.
1578  * See %G_FILE_ATTRIBUTE_STANDARD_SORT_ORDER.
1579  * 
1580  * Returns: a #gint32 containing the value of the "standard::sort_order" attribute.
1581  **/
1582 gint32
1583 g_file_info_get_sort_order (GFileInfo *info)
1584 {
1585   static guint32 attr = 0;
1586   GFileAttributeValue *value;
1587   
1588   g_return_val_if_fail (G_IS_FILE_INFO (info), 0);
1589   
1590   if (attr == 0)
1591     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_SORT_ORDER);
1592   
1593   value = g_file_info_find_value (info, attr);
1594   return _g_file_attribute_value_get_int32 (value);
1595 }
1596
1597 /* Helper setters: */
1598 /**
1599  * g_file_info_set_file_type:
1600  * @info: a #GFileInfo.
1601  * @type: a #GFileType.
1602  * 
1603  * Sets the file type in a #GFileInfo to @type.
1604  * See %G_FILE_ATTRIBUTE_STANDARD_TYPE.
1605  **/
1606 void
1607 g_file_info_set_file_type (GFileInfo *info,
1608                            GFileType  type)
1609 {
1610   static guint32 attr = 0;
1611   GFileAttributeValue *value;
1612   
1613   g_return_if_fail (G_IS_FILE_INFO (info));
1614   
1615   if (attr == 0)
1616     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_TYPE);
1617   
1618   value = g_file_info_create_value (info, attr);
1619   if (value)
1620     _g_file_attribute_value_set_uint32 (value, type);
1621 }
1622
1623 /**
1624  * g_file_info_set_is_hidden:
1625  * @info: a #GFileInfo.
1626  * @is_hidden: a #gboolean.
1627  * 
1628  * Sets the "is_hidden" attribute in a #GFileInfo according to @is_symlink.
1629  * See %G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN.
1630  **/
1631 void
1632 g_file_info_set_is_hidden (GFileInfo *info,
1633                            gboolean   is_hidden)
1634 {
1635   static guint32 attr = 0;
1636   GFileAttributeValue *value;
1637   
1638   g_return_if_fail (G_IS_FILE_INFO (info));
1639   
1640   if (attr == 0)
1641     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN);
1642   
1643   value = g_file_info_create_value (info, attr);
1644   if (value)
1645     _g_file_attribute_value_set_boolean (value, is_hidden);
1646 }
1647
1648 /**
1649  * g_file_info_set_is_symlink:
1650  * @info: a #GFileInfo.
1651  * @is_symlink: a #gboolean.
1652  * 
1653  * Sets the "is_symlink" attribute in a #GFileInfo according to @is_symlink.
1654  * See %G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK.
1655  **/
1656 void
1657 g_file_info_set_is_symlink (GFileInfo *info,
1658                             gboolean   is_symlink)
1659 {
1660   static guint32 attr = 0;
1661   GFileAttributeValue *value;
1662   
1663   g_return_if_fail (G_IS_FILE_INFO (info));
1664   
1665   if (attr == 0)
1666     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK);
1667   
1668   value = g_file_info_create_value (info, attr);
1669   if (value)
1670     _g_file_attribute_value_set_boolean (value, is_symlink);
1671 }
1672
1673 /**
1674  * g_file_info_set_name:
1675  * @info: a #GFileInfo.
1676  * @name: a string containing a name.
1677  * 
1678  * Sets the name attribute for the current #GFileInfo. 
1679  * See %G_FILE_ATTRIBUTE_STANDARD_NAME.
1680  **/
1681 void
1682 g_file_info_set_name (GFileInfo  *info,
1683                       const char *name)
1684 {
1685   static guint32 attr = 0;
1686   GFileAttributeValue *value;
1687   
1688   g_return_if_fail (G_IS_FILE_INFO (info));
1689   g_return_if_fail (name != NULL);
1690   
1691   if (attr == 0)
1692     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_NAME);
1693   
1694   value = g_file_info_create_value (info, attr);
1695   if (value)
1696     _g_file_attribute_value_set_byte_string (value, name);
1697 }
1698
1699 /**
1700  * g_file_info_set_display_name:
1701  * @info: a #GFileInfo.
1702  * @display_name: a string containing a display name.
1703  * 
1704  * Sets the display name for the current #GFileInfo.
1705  * See %G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME.
1706  **/
1707 void
1708 g_file_info_set_display_name (GFileInfo  *info,
1709                               const char *display_name)
1710 {
1711   static guint32 attr = 0;
1712   GFileAttributeValue *value;
1713   
1714   g_return_if_fail (G_IS_FILE_INFO (info));
1715   g_return_if_fail (display_name != NULL);
1716   
1717   if (attr == 0)
1718     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME);
1719   
1720   value = g_file_info_create_value (info, attr);
1721   if (value)
1722     _g_file_attribute_value_set_string (value, display_name);
1723 }
1724
1725 /**
1726  * g_file_info_set_edit_name:
1727  * @info: a #GFileInfo.
1728  * @edit_name: a string containing an edit name.
1729  * 
1730  * Sets the edit name for the current file.
1731  * See %G_FILE_ATTRIBUTE_STANDARD_EDIT_NAME.
1732  **/
1733 void
1734 g_file_info_set_edit_name (GFileInfo  *info,
1735                            const char *edit_name)
1736 {
1737   static guint32 attr = 0;
1738   GFileAttributeValue *value;
1739   
1740   g_return_if_fail (G_IS_FILE_INFO (info));
1741   g_return_if_fail (edit_name != NULL);
1742   
1743   if (attr == 0)
1744     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_EDIT_NAME);
1745   
1746   value = g_file_info_create_value (info, attr);
1747   if (value)
1748     _g_file_attribute_value_set_string (value, edit_name);
1749 }
1750
1751 /**
1752  * g_file_info_set_icon:
1753  * @info: a #GFileInfo.
1754  * @icon: a #GIcon.
1755  * 
1756  * Sets the icon for a given #GFileInfo. 
1757  * See %G_FILE_ATTRIBUTE_STANDARD_ICON.
1758  **/
1759 void
1760 g_file_info_set_icon (GFileInfo *info,
1761                       GIcon     *icon)
1762 {
1763   static guint32 attr = 0;
1764   GFileAttributeValue *value;
1765   
1766   g_return_if_fail (G_IS_FILE_INFO (info));
1767   g_return_if_fail (G_IS_ICON (icon));
1768   
1769   if (attr == 0)
1770     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_ICON);
1771   
1772   value = g_file_info_create_value (info, attr);
1773   if (value)
1774     _g_file_attribute_value_set_object (value, G_OBJECT (icon));
1775 }
1776
1777 /**
1778  * g_file_info_set_content_type:
1779  * @info: a #GFileInfo.
1780  * @content_type: a content type. See #GContentType.
1781  * 
1782  * Sets the content type attribute for a given #GFileInfo.
1783  * See %G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE.
1784  **/
1785 void
1786 g_file_info_set_content_type (GFileInfo  *info,
1787                               const char *content_type)
1788 {
1789   static guint32 attr = 0;
1790   GFileAttributeValue *value;
1791   
1792   g_return_if_fail (G_IS_FILE_INFO (info));
1793   g_return_if_fail (content_type != NULL);
1794   
1795   if (attr == 0)
1796     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE);
1797   
1798   value = g_file_info_create_value (info, attr);
1799   if (value)
1800     _g_file_attribute_value_set_string (value, content_type);
1801 }
1802
1803 /**
1804  * g_file_info_set_size:
1805  * @info: a #GFileInfo.
1806  * @size: a #goffset containing the file's size.
1807  * 
1808  * Sets the %G_FILE_ATTRIBUTE_STANDARD_SIZE attribute in the file info 
1809  * to the given size.
1810  **/
1811 void
1812 g_file_info_set_size (GFileInfo *info,
1813                       goffset    size)
1814 {
1815   static guint32 attr = 0;
1816   GFileAttributeValue *value;
1817   
1818   g_return_if_fail (G_IS_FILE_INFO (info));
1819   
1820   if (attr == 0)
1821     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_SIZE);
1822   
1823   value = g_file_info_create_value (info, attr);
1824   if (value)
1825     _g_file_attribute_value_set_uint64 (value, size);
1826 }
1827
1828 /**
1829  * g_file_info_set_modification_time
1830  * @info: a #GFileInfo.
1831  * @mtime: a #GTimeVal.
1832  * 
1833  * Sets the %G_FILE_ATTRIBUTE_TIME_MODIFIED attribute in the file
1834  * info to the given time value.
1835  **/
1836 void
1837 g_file_info_set_modification_time (GFileInfo *info,
1838                                    GTimeVal  *mtime)
1839 {
1840   static guint32 attr_mtime = 0, attr_mtime_usec;
1841   GFileAttributeValue *value;
1842   
1843   g_return_if_fail (G_IS_FILE_INFO (info));
1844   g_return_if_fail (mtime != NULL);
1845   
1846   if (attr_mtime == 0)
1847     {
1848       attr_mtime = lookup_attribute (G_FILE_ATTRIBUTE_TIME_MODIFIED);
1849       attr_mtime_usec = lookup_attribute (G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC);
1850     }
1851   
1852   value = g_file_info_create_value (info, attr_mtime);
1853   if (value)
1854     _g_file_attribute_value_set_uint64 (value, mtime->tv_sec);
1855   value = g_file_info_create_value (info, attr_mtime_usec);
1856   if (value)
1857     _g_file_attribute_value_set_uint32 (value, mtime->tv_usec);
1858 }
1859
1860 /**
1861  * g_file_info_set_symlink_target:
1862  * @info: a #GFileInfo.
1863  * @symlink_target: a static string containing a path to a symlink target.
1864  * 
1865  * Sets the %G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET attribute in the file info 
1866  * to the given symlink target.
1867  **/
1868 void
1869 g_file_info_set_symlink_target (GFileInfo  *info,
1870                                 const char *symlink_target)
1871 {
1872   static guint32 attr = 0;
1873   GFileAttributeValue *value;
1874   
1875   g_return_if_fail (G_IS_FILE_INFO (info));
1876   g_return_if_fail (symlink_target != NULL);
1877   
1878   if (attr == 0)
1879     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET);
1880   
1881   value = g_file_info_create_value (info, attr);
1882   if (value)
1883     _g_file_attribute_value_set_byte_string (value, symlink_target);
1884 }
1885
1886 /**
1887  * g_file_info_set_sort_order:
1888  * @info: a #GFileInfo.
1889  * @sort_order: a sort order integer.
1890  * 
1891  * Sets the sort order attribute in the file info structure. See 
1892  * %G_FILE_ATTRIBUTE_STANDARD_SORT_ORDER.
1893  **/
1894 void
1895 g_file_info_set_sort_order (GFileInfo *info,
1896                             gint32     sort_order)
1897 {
1898   static guint32 attr = 0;
1899   GFileAttributeValue *value;
1900   
1901   g_return_if_fail (G_IS_FILE_INFO (info));
1902   
1903   if (attr == 0)
1904     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_SORT_ORDER);
1905   
1906   value = g_file_info_create_value (info, attr);
1907   if (value)
1908     _g_file_attribute_value_set_int32 (value, sort_order);
1909 }
1910
1911
1912 #define ON_STACK_MATCHERS 5
1913
1914 typedef struct {
1915   guint32 id;
1916   guint32 mask;
1917 } SubMatcher;
1918
1919 struct _GFileAttributeMatcher {
1920   gboolean all;
1921   SubMatcher sub_matchers[ON_STACK_MATCHERS];
1922   GArray *more_sub_matchers;
1923
1924   /* Interator */
1925   guint32 iterator_ns;
1926   int iterator_pos;
1927   int ref;
1928 };
1929
1930 static void
1931 matcher_add (GFileAttributeMatcher *matcher,
1932              guint                  id,
1933              guint                  mask)
1934 {
1935   SubMatcher *sub_matchers;
1936   int i;
1937   SubMatcher s;
1938
1939   for (i = 0; i < ON_STACK_MATCHERS; i++)
1940     {
1941       /* First empty spot, not found, use this */
1942       if (matcher->sub_matchers[i].id == 0)
1943         {
1944           matcher->sub_matchers[i].id = id;
1945           matcher->sub_matchers[i].mask = mask;
1946           return;
1947         }
1948       
1949       /* Already added */
1950       if (matcher->sub_matchers[i].id == id &&
1951           matcher->sub_matchers[i].mask == mask)
1952         return;
1953     }
1954
1955   if (matcher->more_sub_matchers == NULL)
1956     matcher->more_sub_matchers = g_array_new (FALSE, FALSE, sizeof (SubMatcher));
1957       
1958   sub_matchers = (SubMatcher *)matcher->more_sub_matchers->data;
1959   for (i = 0; i < matcher->more_sub_matchers->len; i++)
1960     {
1961       /* Already added */
1962       if (sub_matchers[i].id == id &&
1963           sub_matchers[i].mask == mask)
1964         return;
1965     }
1966
1967   s.id = id;
1968   s.mask = mask;
1969   
1970   g_array_append_val (matcher->more_sub_matchers, s);
1971 }
1972
1973 /**
1974  * g_file_attribute_matcher_new:
1975  * @attributes: an attribute string to match.
1976  * 
1977  * Creates a new file attribute matcher, which matches attributes 
1978  * against a given string. #GFileAttributeMatcher<!-- -->s are reference 
1979  * counted structures, and are created with a reference count of 1. If 
1980  * the number of references falls to 0, the #GFileAttributeMatcher is 
1981  * automatically destroyed.
1982  * 
1983  * The @attribute string should be formatted with specific keys separated
1984  * from namespaces with a double colon. Several "namespace::key" strings may be 
1985  * concatenated with a single comma (e.g. "standard::type,standard::is-hidden"). 
1986  * The wildcard "*" may be used to match all keys and namespaces, or 
1987  * "namespace::*" will match all keys in a given namespace. 
1988  * 
1989  * Examples of strings to use:
1990  * <table>
1991  * <title>File Attribute Matcher strings and results</title>
1992  * <tgroup cols='2' align='left'><thead>
1993  * <row><entry> Matcher String </entry><entry> Matches </entry></row></thead>
1994  * <tbody>
1995  * <row><entry>"*"</entry><entry>matches all attributes.</entry></row>
1996  * <row><entry>"standard::is-hidden"</entry><entry>matches only the key is-hidden in the standard namespace.</entry></row>
1997  * <row><entry>"standard::type,unix::*"</entry><entry>matches the type key in the standard namespace and
1998  * all keys in the unix namespace.</entry></row>
1999  * </tbody></tgroup>
2000  * </table>
2001  * 
2002  * Returns: a #GFileAttributeMatcher.
2003  **/
2004 GFileAttributeMatcher *
2005 g_file_attribute_matcher_new (const char *attributes)
2006 {
2007   char **split;
2008   char *colon;
2009   int i;
2010   GFileAttributeMatcher *matcher;
2011
2012   if (attributes == NULL || *attributes == '\0')
2013     return NULL;
2014
2015   matcher = g_malloc0 (sizeof (GFileAttributeMatcher));
2016   matcher->ref = 1;
2017
2018   split = g_strsplit (attributes, ",", -1);
2019
2020   for (i = 0; split[i] != NULL; i++)
2021     {
2022       if (strcmp (split[i], "*") == 0)
2023         matcher->all = TRUE;
2024       else
2025         {
2026           guint32 id, mask;
2027   
2028           colon = strstr (split[i], "::");
2029           if (colon != NULL &&
2030               !(colon[2] == 0 ||
2031                 (colon[2] == '*' &&
2032                  colon[3] == 0)))
2033             {
2034               id = lookup_attribute (split[i]);
2035               mask = 0xffffffff;
2036             }
2037           else
2038             {
2039               if (colon)
2040                 *colon = 0;
2041
2042               id = lookup_namespace (split[i]) << NS_POS;
2043               mask = NS_MASK << NS_POS;
2044             }
2045           
2046           matcher_add (matcher, id, mask);
2047         }
2048     }
2049
2050   g_strfreev (split);
2051
2052   return matcher;
2053 }
2054
2055 /**
2056  * g_file_attribute_matcher_ref:
2057  * @matcher: a #GFileAttributeMatcher.
2058  * 
2059  * References a file attribute matcher.
2060  * 
2061  * Returns: a #GFileAttributeMatcher.
2062  **/
2063 GFileAttributeMatcher *
2064 g_file_attribute_matcher_ref (GFileAttributeMatcher *matcher)
2065 {
2066   if (matcher)
2067     {
2068       g_return_val_if_fail (matcher->ref > 0, NULL);
2069       g_atomic_int_inc (&matcher->ref);
2070     }
2071   return matcher;
2072 }
2073
2074 /**
2075  * g_file_attribute_matcher_unref:
2076  * @matcher: a #GFileAttributeMatcher.
2077  * 
2078  * Unreferences @matcher. If the reference count falls below 1, 
2079  * the @matcher is automatically freed.
2080  * 
2081  **/
2082 void
2083 g_file_attribute_matcher_unref (GFileAttributeMatcher *matcher)
2084 {
2085   if (matcher)
2086     {
2087       g_return_if_fail (matcher->ref > 0);
2088       
2089       if (g_atomic_int_dec_and_test (&matcher->ref))
2090         {
2091           if (matcher->more_sub_matchers)
2092             g_array_free (matcher->more_sub_matchers, TRUE);
2093           
2094           g_free (matcher);
2095         }
2096     }
2097 }
2098
2099 /**
2100  * g_file_attribute_matcher_matches_only:
2101  * @matcher: a #GFileAttributeMatcher.
2102  * @attribute: a file attribute key.
2103  * 
2104  * Checks if a attribute matcher only matches a given attribute. Always
2105  * returns %FALSE if "*" was used when creating the matcher.
2106  * 
2107  * Returns: %TRUE if the matcher only matches @attribute. %FALSE otherwise.
2108  **/
2109 gboolean
2110 g_file_attribute_matcher_matches_only (GFileAttributeMatcher *matcher,
2111                                        const char            *attribute)
2112 {
2113   guint32 id;
2114
2115   g_return_val_if_fail (attribute != NULL && *attribute != '\0', FALSE);
2116
2117   if (matcher == NULL ||
2118       matcher->all)
2119     return FALSE;
2120   
2121   id = lookup_attribute (attribute);
2122
2123   if (matcher->sub_matchers[0].id != 0 &&
2124       matcher->sub_matchers[1].id == 0 &&
2125       matcher->sub_matchers[0].mask == 0xffffffff &&
2126       matcher->sub_matchers[0].id == id)
2127     return TRUE;
2128   
2129   return FALSE;
2130 }
2131
2132 static gboolean
2133 matcher_matches_id (GFileAttributeMatcher *matcher,
2134                     guint32                id)
2135 {
2136   SubMatcher *sub_matchers;
2137   int i;
2138   
2139   for (i = 0; i < ON_STACK_MATCHERS; i++)
2140     {
2141       if (matcher->sub_matchers[i].id == 0)
2142         return FALSE;
2143       
2144       if (matcher->sub_matchers[i].id == (id & matcher->sub_matchers[i].mask))
2145         return TRUE;
2146     }
2147
2148   if (matcher->more_sub_matchers)
2149     {
2150       sub_matchers = (SubMatcher *)matcher->more_sub_matchers->data;
2151       for (i = 0; i < matcher->more_sub_matchers->len; i++)
2152         {
2153           if (sub_matchers[i].id == (id & sub_matchers[i].mask))
2154             return TRUE;
2155         }
2156     }
2157   
2158   return FALSE;
2159 }
2160
2161 static gboolean
2162 g_file_attribute_matcher_matches_id (GFileAttributeMatcher *matcher,
2163                                      guint32                id)
2164 {
2165   /* We return a NULL matcher for an empty match string, so handle this */
2166   if (matcher == NULL)
2167     return FALSE;
2168   
2169   if (matcher->all)
2170     return TRUE;
2171   
2172   return matcher_matches_id (matcher, id);
2173 }
2174
2175 /**
2176  * g_file_attribute_matcher_matches:
2177  * @matcher: a #GFileAttributeMatcher.
2178  * @attribute: a file attribute key.
2179  *
2180  * Checks if an attribute will be matched by an attribute matcher. If 
2181  * the matcher was created with the "*" matching string, this function
2182  * will always return %TRUE.
2183  * 
2184  * Returns: %TRUE if @attribute matches @matcher. %FALSE otherwise.
2185  **/
2186 gboolean
2187 g_file_attribute_matcher_matches (GFileAttributeMatcher *matcher,
2188                                   const char            *attribute)
2189 {
2190   g_return_val_if_fail (attribute != NULL && *attribute != '\0', FALSE);
2191
2192   /* We return a NULL matcher for an empty match string, so handle this */
2193   if (matcher == NULL)
2194     return FALSE;
2195   
2196   if (matcher->all)
2197     return TRUE;
2198   
2199   return matcher_matches_id (matcher, lookup_attribute (attribute));
2200 }
2201
2202 /* return TRUE -> all */
2203 /**
2204  * g_file_attribute_matcher_enumerate_namespace:
2205  * @matcher: a #GFileAttributeMatcher.
2206  * @ns: a string containing a file attribute namespace.
2207  * 
2208  * Checks if the matcher will match all of the keys in a given namespace.
2209  * This will always return %TRUE if a wildcard character is in use (e.g. if 
2210  * matcher was created with "standard::*" and @ns is "standard", or if matcher was created
2211  * using "*" and namespace is anything.) 
2212  * 
2213  * TODO: this is awkwardly worded.
2214  * 
2215  * Returns: %TRUE if the matcher matches all of the entries
2216  * in the given @ns, %FALSE otherwise.
2217  **/
2218 gboolean
2219 g_file_attribute_matcher_enumerate_namespace (GFileAttributeMatcher *matcher,
2220                                               const char            *ns)
2221 {
2222   SubMatcher *sub_matchers;
2223   int ns_id;
2224   int i;
2225   
2226   g_return_val_if_fail (ns != NULL && *ns != '\0', FALSE);
2227
2228   /* We return a NULL matcher for an empty match string, so handle this */
2229   if (matcher == NULL)
2230     return FALSE;
2231   
2232   if (matcher->all)
2233     return TRUE;
2234
2235   ns_id = lookup_namespace (ns) << NS_POS;
2236
2237   for (i = 0; i < ON_STACK_MATCHERS; i++)
2238     {
2239       if (matcher->sub_matchers[i].id == ns_id)
2240         return TRUE;
2241     }
2242
2243   if (matcher->more_sub_matchers)
2244     {
2245       sub_matchers = (SubMatcher *)matcher->more_sub_matchers->data;
2246       for (i = 0; i < matcher->more_sub_matchers->len; i++)
2247         {
2248           if (sub_matchers[i].id == ns_id)
2249             return TRUE;
2250         }
2251     }
2252
2253   matcher->iterator_ns = ns_id;
2254   matcher->iterator_pos = 0;
2255   
2256   return FALSE;
2257 }
2258
2259 /**
2260  * g_file_attribute_matcher_enumerate_next:
2261  * @matcher: a #GFileAttributeMatcher.
2262  * 
2263  * Gets the next matched attribute from a #GFileAttributeMatcher.
2264  * 
2265  * Returns: a string containing the next attribute or %NULL if 
2266  * no more attribute exist.
2267  **/
2268 const char *
2269 g_file_attribute_matcher_enumerate_next (GFileAttributeMatcher *matcher)
2270 {
2271   int i;
2272   SubMatcher *sub_matcher;
2273
2274   /* We return a NULL matcher for an empty match string, so handle this */
2275   if (matcher == NULL)
2276     return NULL;
2277
2278   while (1)
2279     {
2280       i = matcher->iterator_pos++;
2281
2282       if (i < ON_STACK_MATCHERS)
2283         {
2284           if (matcher->sub_matchers[i].id == 0)
2285             return NULL;
2286
2287           sub_matcher = &matcher->sub_matchers[i];
2288         }
2289       else
2290         {
2291           if (matcher->more_sub_matchers == NULL)
2292             return NULL;
2293       
2294           i -= ON_STACK_MATCHERS;
2295           if (i < matcher->more_sub_matchers->len)
2296             sub_matcher = &g_array_index (matcher->more_sub_matchers, SubMatcher, i);
2297           else
2298             return NULL;
2299         }
2300
2301       if (sub_matcher->mask == 0xffffffff &&
2302           (sub_matcher->id & (NS_MASK << NS_POS)) == matcher->iterator_ns)
2303         return get_attribute_for_id (sub_matcher->id);
2304     }
2305 }
2306
2307 #define __G_FILE_INFO_C__
2308 #include "gioaliasdef.c"