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