File attribute renames: std:: -> standard:: fs:: -> filesystem:: id::fs ->
[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 @GFileInfo 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  **/
538 void
539 g_file_info_remove_attribute (GFileInfo  *info,
540                               const char *attribute)
541 {
542   guint32 attr_id;
543   GFileAttribute *attrs;
544   int i;
545
546   g_return_if_fail (G_IS_FILE_INFO (info));
547   g_return_if_fail (attribute != NULL && *attribute != '\0');
548
549   attr_id = lookup_attribute (attribute);
550   
551   i = g_file_info_find_place (info, attr_id);
552   attrs = (GFileAttribute *)info->attributes->data;
553   if (i < info->attributes->len &&
554       attrs[i].attribute == attr_id)
555     {
556       _g_file_attribute_value_clear (&attrs[i].value);
557       g_array_remove_index (info->attributes, i);
558     }
559 }
560
561 gboolean
562 g_file_info_get_attribute_data (GFileInfo  *info,
563                                 const char *attribute,
564                                 GFileAttributeType *type,
565                                 gpointer   *value_pp,
566                                 GFileAttributeStatus *status)
567 {
568   GFileAttributeValue *value;
569
570   value = g_file_info_find_value_by_name (info, attribute);
571   if (value == NULL)
572     return FALSE;
573
574   if (status)
575     *status = value->status;
576
577   if (type)
578     *type = value->type;
579
580   if (value_pp)
581     *value_pp = _g_file_attribute_value_peek_as_pointer (value);
582   
583   return TRUE;
584 }
585
586 GFileAttributeStatus
587 g_file_info_get_attribute_status (GFileInfo  *info,
588                                   const char *attribute)
589 {
590   GFileAttributeValue *val;
591   
592   g_return_val_if_fail (G_IS_FILE_INFO (info), 0);
593   g_return_val_if_fail (attribute != NULL && *attribute != '\0', 0);
594
595   val = g_file_info_find_value_by_name (info, attribute);
596   if (val)
597     return val->status;
598
599   return 0;
600 }
601
602
603 GFileAttributeValue *
604 _g_file_info_get_attribute_value (GFileInfo  *info,
605                                   const char *attribute)
606   
607 {
608   g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
609   g_return_val_if_fail (attribute != NULL && *attribute != '\0', NULL);
610
611   return g_file_info_find_value_by_name (info, attribute);
612 }
613
614 /**
615  * g_file_info_get_attribute_as_string:
616  * @info: a #GFileInfo.
617  * @attribute: a file attribute key.
618  * 
619  * Gets the value of a attribute, formated as a string.
620  * This escapes things as needed to make the string valid
621  * utf8.
622  * 
623  * Returns: a utf8 string associated with the given @attribute.
624  *    When you're done with the string it must be freed.
625  **/
626 char *
627 g_file_info_get_attribute_as_string (GFileInfo  *info,
628                                      const char *attribute)
629 {
630   GFileAttributeValue *val;
631   val = _g_file_info_get_attribute_value (info, attribute);
632   if (val) 
633     return _g_file_attribute_value_as_string (val);
634   return NULL;
635 }
636
637
638 /**
639  * g_file_info_get_attribute_object:
640  * @info: a #GFileInfo.
641  * @attribute: a file attribute key.
642  * 
643  * Gets the value of a #GObject attribute. If the attribute does 
644  * not contain a #GObject, %NULL will be returned.
645  * 
646  * Returns: a #GObject associated with the given @attribute, or
647  * %NULL otherwise.
648  **/
649 GObject *
650 g_file_info_get_attribute_object (GFileInfo  *info,
651                                   const char *attribute)
652 {
653   GFileAttributeValue *value;
654   
655   g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
656   g_return_val_if_fail (attribute != NULL && *attribute != '\0', NULL);
657
658   value = g_file_info_find_value_by_name (info, attribute);
659   return _g_file_attribute_value_get_object (value);
660 }
661
662 /**
663  * g_file_info_get_attribute_string:
664  * @info: a #GFileInfo.
665  * @attribute: a file attribute key.
666  * 
667  * Gets the value of a string attribute. If the attribute does 
668  * not contain a string, %NULL will be returned.
669  * 
670  * Returns: the contents of the @attribute value as a string, or 
671  * %NULL otherwise.
672  **/
673 const char *
674 g_file_info_get_attribute_string (GFileInfo  *info,
675                                   const char *attribute)
676 {
677   GFileAttributeValue *value;
678   
679   g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
680   g_return_val_if_fail (attribute != NULL && *attribute != '\0', NULL);
681
682   value = g_file_info_find_value_by_name (info, attribute);
683   return _g_file_attribute_value_get_string (value);
684 }
685
686 /**
687  * g_file_info_get_attribute_byte_string:
688  * @info: a #GFileInfo.
689  * @attribute: a file attribute key.
690  * 
691  * Gets the value of a byte string attribute. If the attribute does 
692  * not contain a byte string, %NULL will be returned.
693  * 
694  * Returns: the contents of the @attribute value as a byte string, or 
695  * %NULL otherwise.
696  **/
697 const char *
698 g_file_info_get_attribute_byte_string (GFileInfo  *info,
699                                        const char *attribute)
700 {
701   GFileAttributeValue *value;
702   
703   g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
704   g_return_val_if_fail (attribute != NULL && *attribute != '\0', NULL);
705
706   value = g_file_info_find_value_by_name (info, attribute);
707   return _g_file_attribute_value_get_byte_string (value);
708 }
709
710 /**
711  * g_file_info_get_attribute_boolean:
712  * @info: a #GFileInfo.
713  * @attribute: a file attribute key.
714  * 
715  * Gets the value of a boolean attribute. If the attribute does not
716  * contain a boolean value, %FALSE will be returned.
717  * 
718  * Returns: the boolean value contained within the attribute. 
719  **/
720 gboolean
721 g_file_info_get_attribute_boolean (GFileInfo  *info,
722                                    const char *attribute)
723 {
724   GFileAttributeValue *value;
725   
726   g_return_val_if_fail (G_IS_FILE_INFO (info), FALSE);
727   g_return_val_if_fail (attribute != NULL && *attribute != '\0', FALSE);
728
729   value = g_file_info_find_value_by_name (info, attribute);
730   return _g_file_attribute_value_get_boolean (value);
731 }
732
733 /**
734  * g_file_info_get_attribute_uint32:
735  * @info: a #GFileInfo.
736  * @attribute: a file attribute key.
737  * 
738  * Gets an unsigned 32-bit integer contained within the attribute. If the 
739  * attribute does not contain an unsigned 32-bit integer, or is invalid, 
740  * 0 will be returned.
741  * 
742  * Returns: an unsigned 32-bit integer from the attribute. 
743  **/
744 guint32
745 g_file_info_get_attribute_uint32 (GFileInfo  *info,
746                                   const char *attribute)
747 {
748   GFileAttributeValue *value;
749   
750   g_return_val_if_fail (G_IS_FILE_INFO (info), 0);
751   g_return_val_if_fail (attribute != NULL && *attribute != '\0', 0);
752
753   value = g_file_info_find_value_by_name (info, attribute);
754   return _g_file_attribute_value_get_uint32 (value);
755 }
756
757 /**
758  * g_file_info_get_attribute_int32:
759  * @info: a #GFileInfo.
760  * @attribute: a file attribute key.
761  * 
762  * Gets a signed 32-bit integer contained within the attribute. If the 
763  * attribute does not contain a signed 32-bit integer, or is invalid, 
764  * 0 will be returned.
765  * 
766  * Returns: a signed 32-bit integer from the attribute.
767  **/
768 gint32
769 g_file_info_get_attribute_int32 (GFileInfo  *info,
770                                  const char *attribute)
771 {
772   GFileAttributeValue *value;
773
774   g_return_val_if_fail (G_IS_FILE_INFO (info), 0);
775   g_return_val_if_fail (attribute != NULL && *attribute != '\0', 0);
776
777   value = g_file_info_find_value_by_name (info, attribute);
778   return _g_file_attribute_value_get_int32 (value);
779 }
780
781 /**
782  * g_file_info_get_attribute_uint64:
783  * @info: a #GFileInfo.
784  * @attribute: a file attribute key.
785  * 
786  * Gets a unsigned 64-bit integer contained within the attribute. If the 
787  * attribute does not contain an unsigned 64-bit integer, or is invalid, 
788  * 0 will be returned.
789  * 
790  * Returns: a unsigned 64-bit integer from the attribute. 
791  **/
792 guint64
793 g_file_info_get_attribute_uint64 (GFileInfo  *info,
794                                   const char *attribute)
795 {
796   GFileAttributeValue *value;
797
798   g_return_val_if_fail (G_IS_FILE_INFO (info), 0);
799   g_return_val_if_fail (attribute != NULL && *attribute != '\0', 0);
800
801   value = g_file_info_find_value_by_name (info, attribute);
802   return _g_file_attribute_value_get_uint64 (value);
803 }
804
805 /**
806  * g_file_info_get_attribute_int64:
807  * @info: a #GFileInfo.
808  * @attribute: a file attribute key.
809  * 
810  * Gets a signed 64-bit integer contained within the attribute. If the 
811  * attribute does not contain an signed 64-bit integer, or is invalid, 
812  * 0 will be returned.
813  * 
814  * Returns: a signed 64-bit integer from the attribute. 
815  **/
816 gint64
817 g_file_info_get_attribute_int64  (GFileInfo  *info,
818                                   const char *attribute)
819 {
820   GFileAttributeValue *value;
821
822   g_return_val_if_fail (G_IS_FILE_INFO (info), 0);
823   g_return_val_if_fail (attribute != NULL && *attribute != '\0', 0);
824
825   value = g_file_info_find_value_by_name (info, attribute);
826   return _g_file_attribute_value_get_int64 (value);
827 }
828
829 static GFileAttributeValue *
830 g_file_info_create_value (GFileInfo *info,
831                           guint32 attr_id)
832 {
833   GFileAttribute *attrs;
834   int i;
835
836   if (info->mask != NO_ATTRIBUTE_MASK &&
837       !g_file_attribute_matcher_matches_id (info->mask, attr_id))
838     return NULL;
839   
840   i = g_file_info_find_place (info, attr_id);
841   
842   attrs = (GFileAttribute *)info->attributes->data;
843   if (i < info->attributes->len &&
844       attrs[i].attribute == attr_id)
845     return &attrs[i].value;
846   else
847     {
848       GFileAttribute attr = { 0 };
849       attr.attribute = attr_id;
850       g_array_insert_val (info->attributes, i, attr);
851
852       attrs = (GFileAttribute *)info->attributes->data;
853       return &attrs[i].value;
854     }
855 }
856
857 static GFileAttributeValue *
858 g_file_info_create_value_by_name (GFileInfo *info,
859                                   const char *attribute)
860 {
861   guint32 attr_id;
862
863   attr_id = lookup_attribute (attribute);
864
865   return g_file_info_create_value (info, attr_id);
866 }
867
868 /**
869  * g_file_info_set_attribute:
870  * @info: a #GFileInfo.
871  * @attribute: a file attribute key.
872  * @type: a #GFileAttributeType
873  * @value_p: pointer to the value
874  * 
875  * Sets the @attribute to contain the given value, if possible.
876  **/
877 void
878 g_file_info_set_attribute (GFileInfo                 *info,
879                            const char                *attribute,
880                            GFileAttributeType         type,
881                            gpointer                   value_p)
882 {
883   GFileAttributeValue *value;
884
885   g_return_if_fail (G_IS_FILE_INFO (info));
886   g_return_if_fail (attribute != NULL && *attribute != '\0');
887
888   value = g_file_info_create_value_by_name (info, attribute);
889
890   if (value)
891     _g_file_attribute_value_set_from_pointer (value, type, value_p, TRUE);
892 }
893
894 /**
895  * g_file_info_set_attribute_object:
896  * @info: a #GFileInfo.
897  * @attribute: a file attribute key.
898  * @attr_value: a #GObject.
899  * 
900  * Sets the @attribute to contain the given @attr_value, 
901  * if possible.
902  **/
903 void
904 g_file_info_set_attribute_object (GFileInfo  *info,
905                                   const char *attribute,
906                                   GObject    *attr_value)
907 {
908   GFileAttributeValue *value;
909
910   g_return_if_fail (G_IS_FILE_INFO (info));
911   g_return_if_fail (attribute != NULL && *attribute != '\0');
912   g_return_if_fail (G_IS_OBJECT (attr_value));
913
914   value = g_file_info_create_value_by_name (info, attribute);
915   if (value)
916     _g_file_attribute_value_set_object (value, attr_value);
917 }
918
919 /**
920  * g_file_info_set_attribute_string:
921  * @info: a #GFileInfo.
922  * @attribute: a file attribute key.
923  * @attr_value: a string.
924  * 
925  * Sets the @attribute to contain the given @attr_value, 
926  * if possible.
927  **/
928 void
929 g_file_info_set_attribute_string (GFileInfo  *info,
930                                   const char *attribute,
931                                   const char *attr_value)
932 {
933   GFileAttributeValue *value;
934   
935   g_return_if_fail (G_IS_FILE_INFO (info));
936   g_return_if_fail (attribute != NULL && *attribute != '\0');
937   g_return_if_fail (attr_value != NULL);
938
939   value = g_file_info_create_value_by_name (info, attribute);
940   if (value)
941     _g_file_attribute_value_set_string (value, attr_value);
942 }
943
944 /**
945  * g_file_info_set_attribute_byte_string:
946  * @info: a #GFileInfo.
947  * @attribute: a file attribute key.
948  * @attr_value: a byte string.
949  * 
950  * Sets the @attribute to contain the given @attr_value, 
951  * if possible.
952  **/
953 void
954 g_file_info_set_attribute_byte_string (GFileInfo  *info,
955                                        const char *attribute,
956                                        const char *attr_value)
957 {
958   GFileAttributeValue *value;
959
960   g_return_if_fail (G_IS_FILE_INFO (info));
961   g_return_if_fail (attribute != NULL && *attribute != '\0');
962   g_return_if_fail (attr_value != NULL);
963
964   value = g_file_info_create_value_by_name (info, attribute);
965   if (value)
966     _g_file_attribute_value_set_byte_string (value, attr_value);
967 }
968
969 /**
970  * g_file_info_set_attribute_boolean:
971  * @info: a #GFileInfo.
972  * @attribute: a file attribute key.
973  * @attr_value: a boolean value.
974  * 
975  * Sets the @attribute to contain the given @attr_value, 
976  * if possible.
977  **/
978 void
979 g_file_info_set_attribute_boolean (GFileInfo  *info,
980                                    const char *attribute,
981                                    gboolean    attr_value)
982 {
983   GFileAttributeValue *value;
984
985   g_return_if_fail (G_IS_FILE_INFO (info));
986   g_return_if_fail (attribute != NULL && *attribute != '\0');
987
988   value = g_file_info_create_value_by_name (info, attribute);
989   if (value)
990     _g_file_attribute_value_set_boolean (value, attr_value);
991 }
992
993 /**
994  * g_file_info_set_attribute_uint32:
995  * @info: a #GFileInfo.
996  * @attribute: a file attribute key.
997  * @attr_value: an unsigned 32-bit integer.
998  * 
999  * Sets the @attribute to contain the given @attr_value, 
1000  * if possible.
1001  **/
1002 void
1003 g_file_info_set_attribute_uint32 (GFileInfo  *info,
1004                                   const char *attribute,
1005                                   guint32     attr_value)
1006 {
1007   GFileAttributeValue *value;
1008
1009   g_return_if_fail (G_IS_FILE_INFO (info));
1010   g_return_if_fail (attribute != NULL && *attribute != '\0');
1011
1012   value = g_file_info_create_value_by_name (info, attribute);
1013   if (value)
1014     _g_file_attribute_value_set_uint32 (value, attr_value);
1015 }
1016
1017
1018 /**
1019  * g_file_info_set_attribute_int32:
1020  * @info: a #GFileInfo.
1021  * @attribute: a file attribute key.
1022  * @attr_value: a signed 32-bit integer
1023  * 
1024  * Sets the @attribute to contain the given @attr_value, 
1025  * if possible.
1026  **/
1027 void
1028 g_file_info_set_attribute_int32 (GFileInfo  *info,
1029                                  const char *attribute,
1030                                  gint32      attr_value)
1031 {
1032   GFileAttributeValue *value;
1033  
1034   g_return_if_fail (G_IS_FILE_INFO (info));
1035   g_return_if_fail (attribute != NULL && *attribute != '\0');
1036
1037   value = g_file_info_create_value_by_name (info, attribute);
1038   if (value)
1039     _g_file_attribute_value_set_int32 (value, attr_value);
1040 }
1041
1042 /**
1043  * g_file_info_set_attribute_uint64:
1044  * @info: a #GFileInfo.
1045  * @attribute: a file attribute key.
1046  * @attr_value: an unsigned 64-bit integer.
1047  * 
1048  * Sets the @attribute to contain the given @attr_value, 
1049  * if possible.
1050  **/
1051 void
1052 g_file_info_set_attribute_uint64 (GFileInfo  *info,
1053                                   const char *attribute,
1054                                   guint64     attr_value)
1055 {
1056   GFileAttributeValue *value;
1057
1058   g_return_if_fail (G_IS_FILE_INFO (info));
1059   g_return_if_fail (attribute != NULL && *attribute != '\0');
1060
1061   value = g_file_info_create_value_by_name (info, attribute);
1062   if (value)
1063     _g_file_attribute_value_set_uint64 (value, attr_value);
1064 }
1065
1066 /**
1067  * g_file_info_set_attribute_int64:
1068  * @info: a #GFileInfo.
1069  * @attribute: attribute name to set.
1070  * @attr_value: int64 value to set attribute to.
1071  * 
1072  * Sets the @attribute to contain the given @attr_value, 
1073  * if possible.
1074  * 
1075  **/
1076 void
1077 g_file_info_set_attribute_int64  (GFileInfo  *info,
1078                                   const char *attribute,
1079                                   gint64      attr_value)
1080 {
1081   GFileAttributeValue *value;
1082
1083   g_return_if_fail (G_IS_FILE_INFO (info));
1084   g_return_if_fail (attribute != NULL && *attribute != '\0');
1085
1086   value = g_file_info_create_value_by_name (info, attribute);
1087   if (value)
1088     _g_file_attribute_value_set_int64 (value, attr_value);
1089 }
1090
1091 /* Helper getters */
1092 /**
1093  * g_file_info_get_file_type:
1094  * @info: a #GFileInfo.
1095  * 
1096  * Gets a file's type (whether it is a regular file, symlink, etc). 
1097  * This is different from the file's content type, see g_file_info_get_content_type().
1098  * 
1099  * Returns: a #GFileType for the given file.
1100  **/
1101 GFileType
1102 g_file_info_get_file_type (GFileInfo *info)
1103 {
1104   static guint32 attr = 0;
1105   GFileAttributeValue *value;
1106
1107   g_return_val_if_fail (G_IS_FILE_INFO (info), G_FILE_TYPE_UNKNOWN);
1108   
1109   if (attr == 0)
1110     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_TYPE);
1111   
1112   value = g_file_info_find_value (info, attr);
1113   return (GFileType)_g_file_attribute_value_get_uint32 (value);
1114 }
1115
1116 /**
1117  * g_file_info_get_is_hidden:
1118  * @info: a #GFileInfo.
1119  * 
1120  * Checks if a file is hidden.
1121  * 
1122  * Returns: %TRUE if the file is a hidden file, %FALSE otherwise.
1123  **/
1124 gboolean
1125 g_file_info_get_is_hidden (GFileInfo *info)
1126 {
1127   static guint32 attr = 0;
1128   GFileAttributeValue *value;
1129   
1130   g_return_val_if_fail (G_IS_FILE_INFO (info), FALSE);
1131   
1132   if (attr == 0)
1133     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN);
1134   
1135   value = g_file_info_find_value (info, attr);
1136   return (GFileType)_g_file_attribute_value_get_boolean (value);
1137 }
1138
1139 /**
1140  * g_file_info_get_is_backup:
1141  * @info: a #GFileInfo.
1142  * 
1143  * Checks if a file is a backup file.
1144  * 
1145  * Returns: %TRUE if file is a backup file, %FALSE otherwise.
1146  **/
1147 gboolean
1148 g_file_info_get_is_backup (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_BACKUP);
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_symlink:
1164  * @info: a #GFileInfo.
1165  * 
1166  * Checks if a file is a symlink.
1167  * 
1168  * Returns: %TRUE if the given @info is a symlink.
1169  **/
1170 gboolean
1171 g_file_info_get_is_symlink (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_SYMLINK);
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_name:
1187  * @info: a #GFileInfo.
1188  * 
1189  * Gets the name for a file.
1190  * 
1191  * Returns: a string containing the file name.
1192  **/
1193 const char *
1194 g_file_info_get_name (GFileInfo *info)
1195 {
1196   static guint32 attr = 0;
1197   GFileAttributeValue *value;
1198   
1199   g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
1200   
1201   if (attr == 0)
1202     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_NAME);
1203   
1204   value = g_file_info_find_value (info, attr);
1205   return _g_file_attribute_value_get_byte_string (value);
1206 }
1207
1208 /**
1209  * g_file_info_get_display_name:
1210  * @info: a #GFileInfo.
1211  * 
1212  * Gets a display name for a file.
1213  * 
1214  * Returns: a string containing the display name.
1215  **/
1216 const char *
1217 g_file_info_get_display_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_DISPLAY_NAME);
1226   
1227   value = g_file_info_find_value (info, attr);
1228   return _g_file_attribute_value_get_string (value);
1229 }
1230
1231 /**
1232  * g_file_info_get_edit_name:
1233  * @info: a #GFileInfo.
1234  * 
1235  * Gets the edit name for a file.
1236  * 
1237  * Returns: a string containing the edit name.
1238  **/
1239 const char *
1240 g_file_info_get_edit_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_EDIT_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_icon:
1256  * @info: a #GFileInfo.
1257  * 
1258  * Gets the icon for a file.
1259  * 
1260  * Returns: #GIcon for the given @info.
1261  **/
1262 GIcon *
1263 g_file_info_get_icon (GFileInfo *info)
1264 {
1265   static guint32 attr = 0;
1266   GFileAttributeValue *value;
1267   GObject *obj;
1268   
1269   g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
1270   
1271   if (attr == 0)
1272     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_ICON);
1273   
1274   value = g_file_info_find_value (info, attr);
1275   obj = _g_file_attribute_value_get_object (value);
1276   if (obj != NULL && G_IS_ICON (obj))
1277     return G_ICON (obj);
1278   return NULL;
1279 }
1280
1281 /**
1282  * g_file_info_get_content_type:
1283  * @info: a #GFileInfo.
1284  * 
1285  * Gets the file's content type.
1286  * 
1287  * Returns: a string containing the file's content type.s
1288  **/
1289 const char *
1290 g_file_info_get_content_type (GFileInfo *info)
1291 {
1292   static guint32 attr = 0;
1293   GFileAttributeValue *value;
1294   
1295   g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
1296   
1297   if (attr == 0)
1298     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE);
1299   
1300   value = g_file_info_find_value (info, attr);
1301   return _g_file_attribute_value_get_string (value);
1302 }
1303
1304 /**
1305  * g_file_info_get_size:
1306  * @info: a #GFileInfo.
1307  * 
1308  * Gets the file's size.
1309  * 
1310  * Returns: a #goffset containing the file's size. 
1311  **/
1312 goffset
1313 g_file_info_get_size (GFileInfo *info)
1314 {
1315   static guint32 attr = 0;
1316   GFileAttributeValue *value;
1317  
1318   g_return_val_if_fail (G_IS_FILE_INFO (info), (goffset) 0);
1319   
1320   if (attr == 0)
1321     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_SIZE);
1322   
1323   value = g_file_info_find_value (info, attr);
1324   return (goffset) _g_file_attribute_value_get_uint64 (value);
1325 }
1326
1327 /**
1328  * g_file_info_get_modification_time:
1329  * @info: a #GFileInfo.
1330  * @result: a #GTimeVal.
1331  * 
1332  * Gets the modification time of the current @info and sets it
1333  * in @result.
1334  **/
1335 void
1336 g_file_info_get_modification_time (GFileInfo *info,
1337                                    GTimeVal  *result)
1338 {
1339   static guint32 attr_mtime = 0, attr_mtime_usec;
1340   GFileAttributeValue *value;
1341
1342   g_return_if_fail (G_IS_FILE_INFO (info));
1343   g_return_if_fail (result != NULL);
1344   
1345   if (attr_mtime == 0)
1346     {
1347       attr_mtime = lookup_attribute (G_FILE_ATTRIBUTE_TIME_MODIFIED);
1348       attr_mtime_usec = lookup_attribute (G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC);
1349     }
1350   
1351   value = g_file_info_find_value (info, attr_mtime);
1352   result->tv_sec = _g_file_attribute_value_get_uint64 (value);
1353   value = g_file_info_find_value (info, attr_mtime_usec);
1354   result->tv_usec = _g_file_attribute_value_get_uint32 (value);
1355 }
1356
1357 /**
1358  * g_file_info_get_symlink_target:
1359  * @info: a #GFileInfo.
1360  * 
1361  * Gets the symlink target for a given #GFileInfo.
1362  * 
1363  * Returns: a string containing the symlink target.
1364  **/
1365 const char *
1366 g_file_info_get_symlink_target (GFileInfo *info)
1367 {
1368   static guint32 attr = 0;
1369   GFileAttributeValue *value;
1370   
1371   g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
1372   
1373   if (attr == 0)
1374     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET);
1375   
1376   value = g_file_info_find_value (info, attr);
1377   return _g_file_attribute_value_get_byte_string (value);
1378 }
1379
1380 /**
1381  * g_file_info_get_etag:
1382  * @info: a #GFileInfo.
1383  * 
1384  * Gets the <link linkend="gfile-etag">entity tag</link> for a given 
1385  * #GFileInfo. See %G_FILE_ATTRIBUTE_ETAG_VALUE.
1386  * 
1387  * Returns: a string containing the value of the "etag:value" attribute.
1388  **/
1389 const char *
1390 g_file_info_get_etag (GFileInfo *info)
1391 {
1392   static guint32 attr = 0;
1393   GFileAttributeValue *value;
1394   
1395   g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
1396   
1397   if (attr == 0)
1398     attr = lookup_attribute (G_FILE_ATTRIBUTE_ETAG_VALUE);
1399   
1400   value = g_file_info_find_value (info, attr);
1401   return _g_file_attribute_value_get_string (value);
1402 }
1403
1404 /**
1405  * g_file_info_get_sort_order:
1406  * @info: a #GFileInfo.
1407  * 
1408  * Gets the value of the sort_order attribute from the #GFileInfo.
1409  * See %G_FILE_ATTRIBUTE_STANDARD_SORT_ORDER.
1410  * 
1411  * Returns: a #gint32 containing the value of the "standard::sort_order" attribute.
1412  **/
1413 gint32
1414 g_file_info_get_sort_order (GFileInfo *info)
1415 {
1416   static guint32 attr = 0;
1417   GFileAttributeValue *value;
1418   
1419   g_return_val_if_fail (G_IS_FILE_INFO (info), 0);
1420   
1421   if (attr == 0)
1422     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_SORT_ORDER);
1423   
1424   value = g_file_info_find_value (info, attr);
1425   return _g_file_attribute_value_get_int32 (value);
1426 }
1427
1428 /* Helper setters: */
1429 /**
1430  * g_file_info_set_file_type:
1431  * @info: a #GFileInfo.
1432  * @type: a #GFileType.
1433  * 
1434  * Sets the file type in a #GFileInfo to @type.
1435  * See %G_FILE_ATTRIBUTE_STANDARD_TYPE.
1436  **/
1437 void
1438 g_file_info_set_file_type (GFileInfo *info,
1439                            GFileType  type)
1440 {
1441   static guint32 attr = 0;
1442   GFileAttributeValue *value;
1443   
1444   g_return_if_fail (G_IS_FILE_INFO (info));
1445   
1446   if (attr == 0)
1447     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_TYPE);
1448   
1449   value = g_file_info_create_value (info, attr);
1450   if (value)
1451     _g_file_attribute_value_set_uint32 (value, type);
1452 }
1453
1454 /**
1455  * g_file_info_set_is_hidden:
1456  * @info: a #GFileInfo.
1457  * @is_hidden: a #gboolean.
1458  * 
1459  * Sets the "is_hidden" attribute in a #GFileInfo according to @is_symlink.
1460  * See %G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN.
1461  **/
1462 void
1463 g_file_info_set_is_hidden (GFileInfo *info,
1464                            gboolean   is_hidden)
1465 {
1466   static guint32 attr = 0;
1467   GFileAttributeValue *value;
1468   
1469   g_return_if_fail (G_IS_FILE_INFO (info));
1470   
1471   if (attr == 0)
1472     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN);
1473   
1474   value = g_file_info_create_value (info, attr);
1475   if (value)
1476     _g_file_attribute_value_set_boolean (value, is_hidden);
1477 }
1478
1479 /**
1480  * g_file_info_set_is_symlink:
1481  * @info: a #GFileInfo.
1482  * @is_symlink: a #gboolean.
1483  * 
1484  * Sets the "is_symlink" attribute in a #GFileInfo according to @is_symlink.
1485  * See %G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK.
1486  **/
1487 void
1488 g_file_info_set_is_symlink (GFileInfo *info,
1489                             gboolean   is_symlink)
1490 {
1491   static guint32 attr = 0;
1492   GFileAttributeValue *value;
1493   
1494   g_return_if_fail (G_IS_FILE_INFO (info));
1495   
1496   if (attr == 0)
1497     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK);
1498   
1499   value = g_file_info_create_value (info, attr);
1500   if (value)
1501     _g_file_attribute_value_set_boolean (value, is_symlink);
1502 }
1503
1504 /**
1505  * g_file_info_set_name:
1506  * @info: a #GFileInfo.
1507  * @name: a string containing a name.
1508  * 
1509  * Sets the name attribute for the current #GFileInfo. 
1510  * See %G_FILE_ATTRIBUTE_STANDARD_NAME.
1511  **/
1512 void
1513 g_file_info_set_name (GFileInfo  *info,
1514                       const char *name)
1515 {
1516   static guint32 attr = 0;
1517   GFileAttributeValue *value;
1518   
1519   g_return_if_fail (G_IS_FILE_INFO (info));
1520   g_return_if_fail (name != NULL);
1521   
1522   if (attr == 0)
1523     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_NAME);
1524   
1525   value = g_file_info_create_value (info, attr);
1526   if (value)
1527     _g_file_attribute_value_set_byte_string (value, name);
1528 }
1529
1530 /**
1531  * g_file_info_set_display_name:
1532  * @info: a #GFileInfo.
1533  * @display_name: a string containing a display name.
1534  * 
1535  * Sets the display name for the current #GFileInfo.
1536  * See %G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME.
1537  **/
1538 void
1539 g_file_info_set_display_name (GFileInfo  *info,
1540                               const char *display_name)
1541 {
1542   static guint32 attr = 0;
1543   GFileAttributeValue *value;
1544   
1545   g_return_if_fail (G_IS_FILE_INFO (info));
1546   g_return_if_fail (display_name != NULL);
1547   
1548   if (attr == 0)
1549     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME);
1550   
1551   value = g_file_info_create_value (info, attr);
1552   if (value)
1553     _g_file_attribute_value_set_string (value, display_name);
1554 }
1555
1556 /**
1557  * g_file_info_set_edit_name:
1558  * @info: a #GFileInfo.
1559  * @edit_name: a string containing an edit name.
1560  * 
1561  * Sets the edit name for the current file.
1562  * See %G_FILE_ATTRIBUTE_STANDARD_EDIT_NAME.
1563  **/
1564 void
1565 g_file_info_set_edit_name (GFileInfo  *info,
1566                            const char *edit_name)
1567 {
1568   static guint32 attr = 0;
1569   GFileAttributeValue *value;
1570   
1571   g_return_if_fail (G_IS_FILE_INFO (info));
1572   g_return_if_fail (edit_name != NULL);
1573   
1574   if (attr == 0)
1575     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_EDIT_NAME);
1576   
1577   value = g_file_info_create_value (info, attr);
1578   if (value)
1579     _g_file_attribute_value_set_string (value, edit_name);
1580 }
1581
1582 /**
1583  * g_file_info_set_icon:
1584  * @info: a #GFileInfo.
1585  * @icon: a #GIcon.
1586  * 
1587  * Sets the icon for a given #GFileInfo. 
1588  * See %G_FILE_ATTRIBUTE_STANDARD_ICON.
1589  **/
1590 void
1591 g_file_info_set_icon (GFileInfo *info,
1592                       GIcon     *icon)
1593 {
1594   static guint32 attr = 0;
1595   GFileAttributeValue *value;
1596   
1597   g_return_if_fail (G_IS_FILE_INFO (info));
1598   g_return_if_fail (G_IS_ICON (icon));
1599   
1600   if (attr == 0)
1601     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_ICON);
1602   
1603   value = g_file_info_create_value (info, attr);
1604   if (value)
1605     _g_file_attribute_value_set_object (value, G_OBJECT (icon));
1606 }
1607
1608 /**
1609  * g_file_info_set_content_type:
1610  * @info: a #GFileInfo.
1611  * @content_type: a content type. See #GContentType.
1612  * 
1613  * Sets the content type attribute for a given #GFileInfo.
1614  * See %G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE.
1615  **/
1616 void
1617 g_file_info_set_content_type (GFileInfo  *info,
1618                               const char *content_type)
1619 {
1620   static guint32 attr = 0;
1621   GFileAttributeValue *value;
1622   
1623   g_return_if_fail (G_IS_FILE_INFO (info));
1624   g_return_if_fail (content_type != NULL);
1625   
1626   if (attr == 0)
1627     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE);
1628   
1629   value = g_file_info_create_value (info, attr);
1630   if (value)
1631     _g_file_attribute_value_set_string (value, content_type);
1632 }
1633
1634 /**
1635  * g_file_info_set_size:
1636  * @info: a #GFileInfo.
1637  * @size: a #goffset containing the file's size.
1638  * 
1639  * Sets the %G_FILE_ATTRIBUTE_STANDARD_SIZE attribute in the file info 
1640  * to the given size.
1641  **/
1642 void
1643 g_file_info_set_size (GFileInfo *info,
1644                       goffset    size)
1645 {
1646   static guint32 attr = 0;
1647   GFileAttributeValue *value;
1648   
1649   g_return_if_fail (G_IS_FILE_INFO (info));
1650   
1651   if (attr == 0)
1652     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_SIZE);
1653   
1654   value = g_file_info_create_value (info, attr);
1655   if (value)
1656     _g_file_attribute_value_set_uint64 (value, size);
1657 }
1658
1659 /**
1660  * g_file_info_set_modification_time
1661  * @info: a #GFileInfo.
1662  * @mtime: a #GTimeVal.
1663  * 
1664  * Sets the %G_FILE_ATTRIBUTE_TIME_MODIFIED attribute in the file
1665  * info to the given time value.
1666  **/
1667 void
1668 g_file_info_set_modification_time (GFileInfo *info,
1669                                    GTimeVal  *mtime)
1670 {
1671   static guint32 attr_mtime = 0, attr_mtime_usec;
1672   GFileAttributeValue *value;
1673   
1674   g_return_if_fail (G_IS_FILE_INFO (info));
1675   g_return_if_fail (mtime != NULL);
1676   
1677   if (attr_mtime == 0)
1678     {
1679       attr_mtime = lookup_attribute (G_FILE_ATTRIBUTE_TIME_MODIFIED);
1680       attr_mtime_usec = lookup_attribute (G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC);
1681     }
1682   
1683   value = g_file_info_create_value (info, attr_mtime);
1684   if (value)
1685     _g_file_attribute_value_set_uint64 (value, mtime->tv_sec);
1686   value = g_file_info_create_value (info, attr_mtime_usec);
1687   if (value)
1688     _g_file_attribute_value_set_uint32 (value, mtime->tv_usec);
1689 }
1690
1691 /**
1692  * g_file_info_set_symlink_target:
1693  * @info: a #GFileInfo.
1694  * @symlink_target: a static string containing a path to a symlink target.
1695  * 
1696  * Sets the %G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET attribute in the file info 
1697  * to the given symlink target.
1698  **/
1699 void
1700 g_file_info_set_symlink_target (GFileInfo  *info,
1701                                 const char *symlink_target)
1702 {
1703   static guint32 attr = 0;
1704   GFileAttributeValue *value;
1705   
1706   g_return_if_fail (G_IS_FILE_INFO (info));
1707   g_return_if_fail (symlink_target != NULL);
1708   
1709   if (attr == 0)
1710     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET);
1711   
1712   value = g_file_info_create_value (info, attr);
1713   if (value)
1714     _g_file_attribute_value_set_byte_string (value, symlink_target);
1715 }
1716
1717 /**
1718  * g_file_info_set_sort_order:
1719  * @info: a #GFileInfo.
1720  * @sort_order: a sort order integer.
1721  * 
1722  * Sets the sort order attribute in the file info structure. See 
1723  * %G_FILE_ATTRIBUTE_STANDARD_SORT_ORDER.
1724  **/
1725 void
1726 g_file_info_set_sort_order (GFileInfo *info,
1727                             gint32     sort_order)
1728 {
1729   static guint32 attr = 0;
1730   GFileAttributeValue *value;
1731   
1732   g_return_if_fail (G_IS_FILE_INFO (info));
1733   
1734   if (attr == 0)
1735     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_SORT_ORDER);
1736   
1737   value = g_file_info_create_value (info, attr);
1738   if (value)
1739     _g_file_attribute_value_set_int32 (value, sort_order);
1740 }
1741
1742
1743 #define ON_STACK_MATCHERS 5
1744
1745 typedef struct {
1746   guint32 id;
1747   guint32 mask;
1748 } SubMatcher;
1749
1750 struct _GFileAttributeMatcher {
1751   gboolean all;
1752   SubMatcher sub_matchers[ON_STACK_MATCHERS];
1753   GArray *more_sub_matchers;
1754
1755   /* Interator */
1756   guint32 iterator_ns;
1757   int iterator_pos;
1758   int ref;
1759 };
1760
1761 static void
1762 matcher_add (GFileAttributeMatcher *matcher,
1763              guint                  id,
1764              guint                  mask)
1765 {
1766   SubMatcher *sub_matchers;
1767   int i;
1768   SubMatcher s;
1769
1770   for (i = 0; i < ON_STACK_MATCHERS; i++)
1771     {
1772       /* First empty spot, not found, use this */
1773       if (matcher->sub_matchers[i].id == 0)
1774         {
1775           matcher->sub_matchers[i].id = id;
1776           matcher->sub_matchers[i].mask = mask;
1777           return;
1778         }
1779       
1780       /* Already added */
1781       if (matcher->sub_matchers[i].id == id &&
1782           matcher->sub_matchers[i].mask == mask)
1783         return;
1784     }
1785
1786   if (matcher->more_sub_matchers == NULL)
1787     matcher->more_sub_matchers = g_array_new (FALSE, FALSE, sizeof (SubMatcher));
1788       
1789   sub_matchers = (SubMatcher *)matcher->more_sub_matchers->data;
1790   for (i = 0; i < matcher->more_sub_matchers->len; i++)
1791     {
1792       /* Already added */
1793       if (sub_matchers[i].id == id &&
1794           sub_matchers[i].mask == mask)
1795         return;
1796     }
1797
1798   s.id = id;
1799   s.mask = mask;
1800   
1801   g_array_append_val (matcher->more_sub_matchers, s);
1802 }
1803
1804 /**
1805  * g_file_attribute_matcher_new:
1806  * @attributes: an attribute string to match.
1807  * 
1808  * Creates a new file attribute matcher, which matches attributes 
1809  * against a given string. #GFileAttributeMatcher<!-- -->s are reference 
1810  * counted structures, and are created with a reference count of 1. If 
1811  * the number of references falls to 0, the #GFileAttributeMatcher is 
1812  * automatically destroyed.
1813  * 
1814  * The @attribute string should be formatted with specific keys separated
1815  * from namespaces with a double colon. Several "namespace::key" strings may be 
1816  * concatenated with a single comma (e.g. "standard::type,standard::is-hidden"). 
1817  * The wildcard "*" may be used to match all keys and namespaces, or 
1818  * "namespace::*" will match all keys in a given namespace. 
1819  * 
1820  * Examples of strings to use:
1821  * <table>
1822  * <title>File Attribute Matcher strings and results</title>
1823  * <tgroup cols='2' align='left'><thead>
1824  * <row><entry> Matcher String </entry><entry> Matches </entry></row></thead>
1825  * <tbody>
1826  * <row><entry>"*"</entry><entry>matches all attributes.</entry></row>
1827  * <row><entry>"standard::is-hidden"</entry><entry>matches only the key is-hidden in the standard namespace.</entry></row>
1828  * <row><entry>"standard::type,unix::*"</entry><entry>matches the type key in the standard namespace and
1829  * all keys in the unix namespace.</entry></row>
1830  * </tbody></tgroup>
1831  * </table>
1832  * 
1833  * Returns: a #GFileAttributeMatcher.
1834  **/
1835 GFileAttributeMatcher *
1836 g_file_attribute_matcher_new (const char *attributes)
1837 {
1838   char **split;
1839   char *colon;
1840   int i;
1841   GFileAttributeMatcher *matcher;
1842
1843   if (attributes == NULL || *attributes == '\0')
1844     return NULL;
1845
1846   matcher = g_malloc0 (sizeof (GFileAttributeMatcher));
1847   matcher->ref = 1;
1848
1849   split = g_strsplit (attributes, ",", -1);
1850
1851   for (i = 0; split[i] != NULL; i++)
1852     {
1853       if (strcmp (split[i], "*") == 0)
1854         matcher->all = TRUE;
1855       else
1856         {
1857           guint32 id, mask;
1858   
1859           colon = strstr (split[i], "::");
1860           if (colon != NULL &&
1861               !(colon[2] == 0 ||
1862                 (colon[2] == '*' &&
1863                  colon[3] == 0)))
1864             {
1865               id = lookup_attribute (split[i]);
1866               mask = 0xffffffff;
1867             }
1868           else
1869             {
1870               if (colon)
1871                 *colon = 0;
1872
1873               id = lookup_namespace (split[i]) << NS_POS;
1874               mask = NS_MASK << NS_POS;
1875             }
1876           
1877           matcher_add (matcher, id, mask);
1878         }
1879     }
1880
1881   g_strfreev (split);
1882
1883   return matcher;
1884 }
1885
1886 /**
1887  * g_file_attribute_matcher_ref:
1888  * @matcher: a #GFileAttributeMatcher.
1889  * 
1890  * References a file attribute matcher.
1891  * 
1892  * Returns: a #GFileAttributeMatcher.
1893  **/
1894 GFileAttributeMatcher *
1895 g_file_attribute_matcher_ref (GFileAttributeMatcher *matcher)
1896 {
1897   g_return_val_if_fail (matcher != NULL, NULL);
1898   g_return_val_if_fail (matcher->ref > 0, NULL);
1899
1900   g_atomic_int_inc (&matcher->ref);
1901   
1902   return matcher;
1903 }
1904
1905 /**
1906  * g_file_attribute_matcher_unref:
1907  * @matcher: a #GFileAttributeMatcher.
1908  * 
1909  * Unreferences @matcher. If the reference count falls below 1, 
1910  * the @matcher is automatically freed.
1911  * 
1912  **/
1913 void
1914 g_file_attribute_matcher_unref (GFileAttributeMatcher *matcher)
1915 {
1916   g_return_if_fail (matcher != NULL);
1917   g_return_if_fail (matcher->ref > 0);
1918
1919   if (g_atomic_int_dec_and_test (&matcher->ref))
1920     {
1921       if (matcher->more_sub_matchers)
1922         g_array_free (matcher->more_sub_matchers, TRUE);
1923       
1924       g_free (matcher);
1925     }
1926 }
1927
1928 /**
1929  * g_file_attribute_matcher_matches_only:
1930  * @matcher: a #GFileAttributeMatcher.
1931  * @attribute: a file attribute key.
1932  * 
1933  * Checks if a attribute matcher only matches a given attribute. Always
1934  * returns %FALSE if "*" was used when creating the matcher.
1935  * 
1936  * Returns: %TRUE if the matcher only matches @attribute. %FALSE otherwise.
1937  **/
1938 gboolean
1939 g_file_attribute_matcher_matches_only (GFileAttributeMatcher *matcher,
1940                                        const char            *attribute)
1941 {
1942   guint32 id;
1943
1944   g_return_val_if_fail (matcher != NULL, FALSE);
1945   g_return_val_if_fail (attribute != NULL && *attribute != '\0', FALSE);
1946
1947   if (matcher->all)
1948     return FALSE;
1949   
1950   id = lookup_attribute (attribute);
1951
1952   if (matcher->sub_matchers[0].id != 0 &&
1953       matcher->sub_matchers[1].id == 0 &&
1954       matcher->sub_matchers[0].mask == 0xffffffff &&
1955       matcher->sub_matchers[0].id == id)
1956     return TRUE;
1957   
1958   return FALSE;
1959 }
1960
1961 static gboolean
1962 matcher_matches_id (GFileAttributeMatcher *matcher,
1963                     guint32                id)
1964 {
1965   SubMatcher *sub_matchers;
1966   int i;
1967   
1968   for (i = 0; i < ON_STACK_MATCHERS; i++)
1969     {
1970       if (matcher->sub_matchers[i].id == 0)
1971         return FALSE;
1972       
1973       if (matcher->sub_matchers[i].id == (id & matcher->sub_matchers[i].mask))
1974         return TRUE;
1975     }
1976
1977   if (matcher->more_sub_matchers)
1978     {
1979       sub_matchers = (SubMatcher *)matcher->more_sub_matchers->data;
1980       for (i = 0; i < matcher->more_sub_matchers->len; i++)
1981         {
1982           if (sub_matchers[i].id == (id & sub_matchers[i].mask))
1983             return TRUE;
1984         }
1985     }
1986   
1987   return FALSE;
1988 }
1989
1990 static gboolean
1991 g_file_attribute_matcher_matches_id (GFileAttributeMatcher *matcher,
1992                                      guint32                id)
1993 {
1994   g_return_val_if_fail (matcher != NULL, FALSE);
1995   
1996   if (matcher->all)
1997     return TRUE;
1998   
1999   return matcher_matches_id (matcher, id);
2000 }
2001
2002 /**
2003  * g_file_attribute_matcher_matches:
2004  * @matcher: a #GFileAttributeMatcher.
2005  * @attribute: a file attribute key.
2006  *
2007  * Checks if an attribute will be matched by an attribute matcher. If 
2008  * the matcher was created with the "*" matching string, this function
2009  * will always return %TRUE.
2010  * 
2011  * Returns: %TRUE if @attribute matches @matcher. %FALSE otherwise.
2012  **/
2013 gboolean
2014 g_file_attribute_matcher_matches (GFileAttributeMatcher *matcher,
2015                                   const char            *attribute)
2016 {
2017   g_return_val_if_fail (matcher != NULL, FALSE);
2018   g_return_val_if_fail (attribute != NULL && *attribute != '\0', FALSE);
2019
2020   if (matcher->all)
2021     return TRUE;
2022   
2023   return matcher_matches_id (matcher, lookup_attribute (attribute));
2024 }
2025
2026 /* return TRUE -> all */
2027 /**
2028  * g_file_attribute_matcher_enumerate_namespace:
2029  * @matcher: a #GFileAttributeMatcher.
2030  * @ns: a string containing a file attribute namespace.
2031  * 
2032  * Checks if the matcher will match all of the keys in a given namespace.
2033  * This will always return %TRUE if a wildcard character is in use (e.g. if 
2034  * matcher was created with "standard::*" and @ns is "standard", or if matcher was created
2035  * using "*" and namespace is anything.) 
2036  * 
2037  * TODO: this is awkwardly worded.
2038  * 
2039  * Returns: %TRUE if the matcher matches all of the entries
2040  * in the given @ns, %FALSE otherwise.
2041  **/
2042 gboolean
2043 g_file_attribute_matcher_enumerate_namespace (GFileAttributeMatcher *matcher,
2044                                               const char            *ns)
2045 {
2046   SubMatcher *sub_matchers;
2047   int ns_id;
2048   int i;
2049   
2050   g_return_val_if_fail (matcher != NULL, FALSE);
2051   g_return_val_if_fail (ns != NULL && *ns != '\0', FALSE);
2052   
2053   if (matcher->all)
2054     return TRUE;
2055
2056   ns_id = lookup_namespace (ns) << NS_POS;
2057
2058   for (i = 0; i < ON_STACK_MATCHERS; i++)
2059     {
2060       if (matcher->sub_matchers[i].id == ns_id)
2061         return TRUE;
2062     }
2063
2064   if (matcher->more_sub_matchers)
2065     {
2066       sub_matchers = (SubMatcher *)matcher->more_sub_matchers->data;
2067       for (i = 0; i < matcher->more_sub_matchers->len; i++)
2068         {
2069           if (sub_matchers[i].id == ns_id)
2070             return TRUE;
2071         }
2072     }
2073
2074   matcher->iterator_ns = ns_id;
2075   matcher->iterator_pos = 0;
2076   
2077   return FALSE;
2078 }
2079
2080 /**
2081  * g_file_attribute_matcher_enumerate_next:
2082  * @matcher: a #GFileAttributeMatcher.
2083  * 
2084  * Gets the next matched attribute from a #GFileAttributeMatcher.
2085  * 
2086  * Returns: a string containing the next attribute or %NULL if 
2087  * no more attribute exist.
2088  **/
2089 const char *
2090 g_file_attribute_matcher_enumerate_next (GFileAttributeMatcher *matcher)
2091 {
2092   int i;
2093   SubMatcher *sub_matcher;
2094   
2095   g_return_val_if_fail (matcher != NULL, NULL);
2096
2097   while (1)
2098     {
2099       i = matcher->iterator_pos++;
2100
2101       if (i < ON_STACK_MATCHERS)
2102         {
2103           if (matcher->sub_matchers[i].id == 0)
2104             return NULL;
2105
2106           sub_matcher = &matcher->sub_matchers[i];
2107         }
2108       else
2109         {
2110           if (matcher->more_sub_matchers == NULL)
2111             return NULL;
2112       
2113           i -= ON_STACK_MATCHERS;
2114           if (i < matcher->more_sub_matchers->len)
2115             sub_matcher = &g_array_index (matcher->more_sub_matchers, SubMatcher, i);
2116           else
2117             return NULL;
2118         }
2119
2120       if (sub_matcher->mask == 0xffffffff &&
2121           (sub_matcher->id & (NS_MASK << NS_POS)) == matcher->iterator_ns)
2122         return get_attribute_for_id (sub_matcher->id);
2123     }
2124 }
2125
2126 #define __G_FILE_INFO_C__
2127 #include "gioaliasdef.c"