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