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