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