Bumps documentation to 93% symbol coverage, touching most
[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 KILOBYTE_FACTOR 1024.0
1707 #define MEGABYTE_FACTOR (1024.0 * 1024.0)
1708 #define GIGABYTE_FACTOR (1024.0 * 1024.0 * 1024.0)
1709
1710 /**
1711  * g_format_file_size_for_display:
1712  * @size: a file size.
1713  * 
1714  * Formats a file size into a human readable string. Sizes are rounded
1715  * to the nearest metric prefix and are displayed rounded to the nearest 
1716  * tenth. E.g. the file size 3292528 bytes will be converted into the string 
1717  * "3.1 MB".
1718  * 
1719  * Returns: a formatted string containing a human readable file size.
1720  **/
1721 char *
1722 g_format_file_size_for_display (goffset size)
1723 {
1724   if (size < (goffset) KILOBYTE_FACTOR)
1725     return g_strdup_printf (dngettext(GETTEXT_PACKAGE, "%u byte", "%u bytes",(guint) size), (guint) size);
1726   else
1727     {
1728       gdouble displayed_size;
1729       
1730       if (size < (goffset) MEGABYTE_FACTOR)
1731         {
1732           displayed_size = (gdouble) size / KILOBYTE_FACTOR;
1733           return g_strdup_printf (_("%.1f KB"), displayed_size);
1734         }
1735       else if (size < (goffset) GIGABYTE_FACTOR)
1736         {
1737           displayed_size = (gdouble) size / MEGABYTE_FACTOR;
1738           return g_strdup_printf (_("%.1f MB"), displayed_size);
1739         }
1740       else
1741         {
1742           displayed_size = (gdouble) size / GIGABYTE_FACTOR;
1743           return g_strdup_printf (_("%.1f GB"), displayed_size);
1744         }
1745     }
1746 }
1747
1748 #define ON_STACK_MATCHERS 5
1749
1750 typedef struct {
1751   guint32 id;
1752   guint32 mask;
1753 } SubMatcher;
1754
1755 struct _GFileAttributeMatcher {
1756   gboolean all;
1757   SubMatcher sub_matchers[ON_STACK_MATCHERS];
1758   GArray *more_sub_matchers;
1759
1760   /* Interator */
1761   guint32 iterator_ns;
1762   int iterator_pos;
1763   int ref;
1764 };
1765
1766 static void
1767 matcher_add (GFileAttributeMatcher *matcher,
1768              guint id, guint mask)
1769 {
1770   SubMatcher *sub_matchers;
1771   int i;
1772   SubMatcher s;
1773
1774   for (i = 0; i < ON_STACK_MATCHERS; i++)
1775     {
1776       /* First empty spot, not found, use this */
1777       if (matcher->sub_matchers[i].id == 0)
1778         {
1779           matcher->sub_matchers[i].id = id;
1780           matcher->sub_matchers[i].mask = mask;
1781           return;
1782         }
1783       
1784       /* Already added */
1785       if (matcher->sub_matchers[i].id == id &&
1786           matcher->sub_matchers[i].mask == mask)
1787         return;
1788     }
1789
1790   if (matcher->more_sub_matchers == NULL)
1791     matcher->more_sub_matchers = g_array_new (FALSE, FALSE, sizeof (SubMatcher));
1792       
1793   sub_matchers = (SubMatcher *)matcher->more_sub_matchers->data;
1794   for (i = 0; i < matcher->more_sub_matchers->len; i++)
1795     {
1796       /* Already added */
1797       if (sub_matchers[i].id == id &&
1798           sub_matchers[i].mask == mask)
1799         return;
1800     }
1801
1802   s.id = id;
1803   s.mask = mask;
1804   
1805   g_array_append_val (matcher->more_sub_matchers, s);
1806 }
1807
1808 /**
1809  * g_file_attribute_matcher_new:
1810  * @attributes: an attribute string to match.
1811  * 
1812  * Creates a new file attribute matcher, which matches attributes against
1813  * a given string. #GFileAttributeMatcher<!-- -->s are reference counted structures, 
1814  * and are created with a reference count of 1. If the number of references
1815  * falls to 0, the #GFileAttributeMatcher is automatically destroyed.
1816  * 
1817  * The @attribute string should be formatted with specific keys separated
1818  * from namespaces with a colon. Several "namespace:key" strings may be 
1819  * concatenated with a single comma (e.g. "std:type,std:is_hidden"). 
1820  * The wildcard "*" may be used to match all keys and namespaces, or "namespace:*" will 
1821  * match all keys in a given namespace. 
1822  * 
1823  * Examples of strings to use:
1824  * <table>
1825  * <title>File Attribute Matcher strings and results</title>
1826  * <tgroup cols='2' align='left'><thead>
1827  * <row><entry> Matcher String </entry><entry> Matches </entry></row></thead>
1828  * <tbody>
1829  * <row><entry>"*"</entry><entry>matches all attributes.</entry></row>
1830  * <row><entry>"std:is_hidden"</entry><entry>matches only the key is_hidden in the std namespace.</entry></row>
1831  * <row><entry>"std:type,unix:*"</entry><entry>matches the type key in the std namespace and all keys in the unix 
1832  * namespace.</entry></row>
1833  * </tbody></tgroup>
1834  * </table>
1835  * 
1836  * Returns: a #GFileAttributeMatcher.
1837  **/
1838 GFileAttributeMatcher *
1839 g_file_attribute_matcher_new (const char *attributes)
1840 {
1841   char **split;
1842   char *colon;
1843   int i;
1844   GFileAttributeMatcher *matcher;
1845
1846   if (attributes == NULL || *attributes == '\0')
1847     return NULL;
1848
1849   matcher = g_malloc0 (sizeof (GFileAttributeMatcher));
1850   matcher->ref = 1;
1851
1852   split = g_strsplit (attributes, ",", -1);
1853
1854   for (i = 0; split[i] != NULL; i++)
1855     {
1856       if (strcmp (split[i], "*") == 0)
1857         matcher->all = TRUE;
1858       else
1859         {
1860           guint32 id, mask;
1861   
1862           colon = strchr (split[i], ':');
1863           if (colon != NULL &&
1864               !(colon[1] == 0 ||
1865                 (colon[1] == '*' &&
1866                  colon[2] == 0)))
1867             {
1868               id = lookup_attribute (split[i]);
1869               mask = 0xffffffff;
1870             }
1871           else
1872             {
1873               if (colon)
1874                 *colon = 0;
1875
1876               id = lookup_namespace (split[i]) << NS_POS;
1877               mask = NS_MASK << NS_POS;
1878             }
1879           
1880           matcher_add (matcher, id, mask);
1881         }
1882     }
1883
1884   g_strfreev (split);
1885
1886   return matcher;
1887 }
1888
1889 /**
1890  * g_file_attribute_matcher_ref:
1891  * @matcher: a #GFileAttributeMatcher.
1892  * 
1893  * References a file attribute matcher.
1894  * 
1895  * Returns: a #GFileAttributeMatcher.
1896  **/
1897 GFileAttributeMatcher *
1898 g_file_attribute_matcher_ref (GFileAttributeMatcher *matcher)
1899 {
1900   g_return_val_if_fail (matcher != NULL, NULL);
1901   g_return_val_if_fail (matcher->ref > 0, NULL);
1902
1903   g_atomic_int_inc (&matcher->ref);
1904   
1905   return matcher;
1906 }
1907
1908 /**
1909  * g_file_attribute_matcher_unref:
1910  * @matcher: a #GFileAttributeMatcher.
1911  * 
1912  * Unreferences @matcher. If the reference count falls below 1, 
1913  * the @matcher is automatically freed.
1914  * 
1915  **/
1916 void
1917 g_file_attribute_matcher_unref (GFileAttributeMatcher *matcher)
1918 {
1919   g_return_if_fail (matcher != NULL);
1920   g_return_if_fail (matcher->ref > 0);
1921
1922   if (g_atomic_int_dec_and_test (&matcher->ref))
1923     {
1924       if (matcher->more_sub_matchers)
1925         g_array_free (matcher->more_sub_matchers, TRUE);
1926       
1927       g_free (matcher);
1928     }
1929 }
1930
1931 /**
1932  * g_file_attribute_matcher_matches_only:
1933  * @matcher: a #GFileAttributeMatcher.
1934  * @attribute: a file attribute key.
1935  * 
1936  * Checks if a attribute matcher only matches a given attribute. Always
1937  * returns %FALSE if "*" was used when creating the matcher.
1938  * 
1939  * Returns: %TRUE if the matcher only matches @attribute. %FALSE otherwise.
1940  **/
1941 gboolean
1942 g_file_attribute_matcher_matches_only (GFileAttributeMatcher *matcher,
1943                                        const char            *attribute)
1944 {
1945   guint32 id;
1946
1947   g_return_val_if_fail (matcher != NULL, FALSE);
1948   g_return_val_if_fail (attribute != NULL && *attribute != '\0', FALSE);
1949
1950   if (matcher->all)
1951     return FALSE;
1952   
1953   id = lookup_attribute (attribute);
1954
1955   if (matcher->sub_matchers[0].id != 0 &&
1956       matcher->sub_matchers[1].id == 0 &&
1957       matcher->sub_matchers[0].mask == 0xffffffff &&
1958       matcher->sub_matchers[0].id == id)
1959     return TRUE;
1960   
1961   return FALSE;
1962 }
1963
1964 static gboolean
1965 matcher_matches_id (GFileAttributeMatcher *matcher,
1966                     guint32 id)
1967 {
1968   SubMatcher *sub_matchers;
1969   int i;
1970   
1971   for (i = 0; i < ON_STACK_MATCHERS; i++)
1972     {
1973       if (matcher->sub_matchers[i].id == 0)
1974         return FALSE;
1975       
1976       if (matcher->sub_matchers[i].id == (id & matcher->sub_matchers[i].mask))
1977         return TRUE;
1978     }
1979
1980   if (matcher->more_sub_matchers)
1981     {
1982       sub_matchers = (SubMatcher *)matcher->more_sub_matchers->data;
1983       for (i = 0; i < matcher->more_sub_matchers->len; i++)
1984         {
1985           if (sub_matchers[i].id == (id & sub_matchers[i].mask))
1986             return TRUE;
1987         }
1988     }
1989   
1990   return FALSE;
1991 }
1992
1993 static gboolean
1994 g_file_attribute_matcher_matches_id (GFileAttributeMatcher *matcher,
1995                                      guint32 id)
1996 {
1997   g_return_val_if_fail (matcher != NULL, FALSE);
1998   
1999   if (matcher->all)
2000     return TRUE;
2001   
2002   return matcher_matches_id (matcher, id);
2003 }
2004
2005 /**
2006  * g_file_attribute_matcher_matches:
2007  * @matcher: a #GFileAttributeMatcher.
2008  * @attribute: a file attribute key.
2009  *
2010  * Checks if an attribute will be matched by an attribute matcher. If 
2011  * the matcher was created with the "*" matching string, this function
2012  * will always return %TRUE.
2013  * 
2014  * Returns: %TRUE if @attribute matches @matcher. %FALSE otherwise.
2015  **/
2016 gboolean
2017 g_file_attribute_matcher_matches (GFileAttributeMatcher *matcher,
2018                                   const char            *attribute)
2019 {
2020   g_return_val_if_fail (matcher != NULL, FALSE);
2021   g_return_val_if_fail (attribute != NULL && *attribute != '\0', FALSE);
2022
2023   if (matcher->all)
2024     return TRUE;
2025   
2026   return matcher_matches_id (matcher, lookup_attribute (attribute));
2027 }
2028
2029 /* return TRUE -> all */
2030 /**
2031  * g_file_attribute_matcher_enumerate_namespace:
2032  * @matcher: a #GFileAttributeMatcher.
2033  * @ns: a string containing a file attribute namespace.
2034  * 
2035  * Checks if the matcher will match all of the keys in a given namespace.
2036  * This will always return %TRUE if a wildcard character is in use (e.g. if 
2037  * matcher was created with "std:*" and @ns is "std", or if matcher was created
2038  * using "*" and namespace is anything.) 
2039  * 
2040  * TODO: this is awkwardly worded.
2041  * 
2042  * Returns: %TRUE if the matcher matches all of the entries
2043  * in the given @ns, %FALSE otherwise.
2044  **/
2045 gboolean
2046 g_file_attribute_matcher_enumerate_namespace (GFileAttributeMatcher *matcher,
2047                                               const char            *ns)
2048 {
2049   SubMatcher *sub_matchers;
2050   int ns_id;
2051   int i;
2052   
2053   g_return_val_if_fail (matcher != NULL, FALSE);
2054   g_return_val_if_fail (ns != NULL && *ns != '\0', FALSE);
2055   
2056   if (matcher->all)
2057     return TRUE;
2058
2059   ns_id = lookup_namespace (ns) << NS_POS;
2060
2061   for (i = 0; i < ON_STACK_MATCHERS; i++)
2062     {
2063       if (matcher->sub_matchers[i].id == ns_id)
2064         return TRUE;
2065     }
2066
2067   if (matcher->more_sub_matchers)
2068     {
2069       sub_matchers = (SubMatcher *)matcher->more_sub_matchers->data;
2070       for (i = 0; i < matcher->more_sub_matchers->len; i++)
2071         {
2072           if (sub_matchers[i].id == ns_id)
2073             return TRUE;
2074         }
2075     }
2076
2077   matcher->iterator_ns = ns_id;
2078   matcher->iterator_pos = 0;
2079   
2080   return FALSE;
2081 }
2082
2083 /**
2084  * g_file_attribute_matcher_enumerate_next:
2085  * @matcher: a #GFileAttributeMatcher.
2086  * 
2087  * Gets the next matched attribute from a #GFileAttributeMatcher.
2088  * 
2089  * Returns: a string containing the next attribute or %NULL if 
2090  * no more attribute exist.
2091  **/
2092 const char *
2093 g_file_attribute_matcher_enumerate_next (GFileAttributeMatcher *matcher)
2094 {
2095   int i;
2096   SubMatcher *sub_matcher;
2097   
2098   g_return_val_if_fail (matcher != NULL, NULL);
2099
2100   while (1)
2101     {
2102       i = matcher->iterator_pos++;
2103
2104       if (i < ON_STACK_MATCHERS)
2105         {
2106           if (matcher->sub_matchers[i].id == 0)
2107             return NULL;
2108
2109           sub_matcher = &matcher->sub_matchers[i];
2110         }
2111       else
2112         {
2113           if (matcher->more_sub_matchers == NULL)
2114             return NULL;
2115       
2116           i -= ON_STACK_MATCHERS;
2117           if (i < matcher->more_sub_matchers->len)
2118             sub_matcher = &g_array_index (matcher->more_sub_matchers, SubMatcher, i);
2119           else
2120             return NULL;
2121         }
2122
2123       if (sub_matcher->mask == 0xffffffff &&
2124           (sub_matcher->id & (NS_MASK << NS_POS)) == matcher->iterator_ns)
2125         return get_attribute_for_id (sub_matcher->id);
2126     }
2127 }