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