Merge remote branch 'gvdb/master'
[platform/upstream/glib.git] / gio / gfileinfo.c
1 /* GIO - GLib Input, Output and Streaming Library
2  * 
3  * Copyright (C) 2006-2007 Red Hat, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General
16  * Public License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18  * Boston, MA 02111-1307, USA.
19  *
20  * Author: Alexander Larsson <alexl@redhat.com>
21  */
22
23 /**
24  * SECTION:gfileinfo
25  * @short_description: File Information and Attributes
26  * @include: gio/gio.h
27  * @see_also: #GFile, <link linkend="gio-GFileAttribute">GFileAttribute</link>
28  *
29  * Functionality for manipulating basic metadata for files. #GFileInfo
30  * implements methods for getting information that all files should
31  * contain, and allows for manipulation of extended attributes.
32  *
33  * See <link linkend="gio-GFileAttribute">GFileAttribute</link> for more
34  * information on how GIO handles file attributes.
35  *
36  * To obtain a #GFileInfo for a #GFile, use g_file_query_info() (or its
37  * async variant). To obtain a #GFileInfo for a file input or output
38  * stream, use g_file_input_stream_query_info() or
39  * g_file_output_stream_query_info() (or their async variants).
40  *
41  * To change the actual attributes of a file, you should then set the
42  * attribute in the #GFileInfo and call g_file_set_attributes_from_info()
43  * or g_file_set_attributes_async() on a GFile.
44  *
45  * However, not all attributes can be changed in the file. For instance,
46  * the actual size of a file cannot be changed via g_file_info_set_size().
47  * You may call g_file_query_settable_attributes() and
48  * g_file_query_writable_namespaces() to discover the settable attributes
49  * of a particular file at runtime.
50  *
51  * #GFileAttributeMatcher allows for searching through a #GFileInfo for
52  * attributes.
53  **/
54
55 #include "config.h"
56
57 #include <string.h>
58
59 #include "gfileinfo.h"
60 #include "gfileinfo-priv.h"
61 #include "gfileattribute-priv.h"
62 #include "gicon.h"
63 #include "glibintl.h"
64
65 #include "gioalias.h"
66
67 /* We use this nasty thing, because NULL is a valid attribute matcher (matches nothing) */
68 #define NO_ATTRIBUTE_MASK ((GFileAttributeMatcher *)1)
69
70 typedef struct  {
71   guint32 attribute;
72   GFileAttributeValue value;
73 } GFileAttribute;
74
75 struct _GFileInfo
76 {
77   GObject parent_instance;
78
79   GArray *attributes;
80   GFileAttributeMatcher *mask;
81 };
82
83 struct _GFileInfoClass
84 {
85   GObjectClass parent_class;
86 };
87
88
89 G_DEFINE_TYPE (GFileInfo, g_file_info, G_TYPE_OBJECT);
90
91 typedef struct {
92   guint32 id;
93   guint32 attribute_id_counter;
94 } NSInfo;
95
96 G_LOCK_DEFINE_STATIC (attribute_hash);
97 static int namespace_id_counter = 0;
98 static GHashTable *ns_hash = NULL;
99 static GHashTable *attribute_hash = NULL;
100 static char ***attributes = NULL;
101
102 /* Attribute ids are 32bit, we split it up like this:
103  * |------------|--------------------|
104  *   12 bit          20 bit       
105  *   namespace      attribute id    
106  *
107  * This way the attributes gets sorted in namespace order
108  */
109
110 #define NS_POS 20
111 #define NS_MASK ((guint32)((1<<12) - 1))
112 #define ID_POS 0
113 #define ID_MASK ((guint32)((1<<20) - 1))
114
115 #define GET_NS(_attr_id) \
116     (((guint32) (_attr_id) >> NS_POS) & NS_MASK)
117 #define GET_ID(_attr_id) \
118     (((guint32)(_attr_id) >> ID_POS) & ID_MASK)
119
120 #define MAKE_ATTR_ID(_ns, _id)                          \
121     ( ((((guint32) _ns) & NS_MASK) << NS_POS) |         \
122       ((((guint32) _id) & ID_MASK) << ID_POS) )
123
124 static NSInfo *
125 _lookup_namespace (const char *namespace)
126 {
127   NSInfo *ns_info;
128   
129   ns_info = g_hash_table_lookup (ns_hash, namespace);
130   if (ns_info == NULL)
131     {
132       ns_info = g_new0 (NSInfo, 1);
133       ns_info->id = ++namespace_id_counter;
134       g_hash_table_insert (ns_hash, g_strdup (namespace), ns_info);
135       attributes = g_realloc (attributes, (ns_info->id + 1) * sizeof (char **));
136       attributes[ns_info->id] = NULL;
137     }
138   return ns_info;
139 }
140
141 static guint32
142 _lookup_attribute (const char *attribute)
143 {
144   guint32 attr_id, id;
145   char *ns;
146   const char *colon;
147   NSInfo *ns_info;
148   
149   attr_id = GPOINTER_TO_UINT (g_hash_table_lookup (attribute_hash, attribute));
150
151   if (attr_id != 0)
152     return attr_id;
153
154   colon = strstr (attribute, "::");
155   if (colon)
156     ns = g_strndup (attribute, colon - attribute);
157   else
158     ns = g_strdup ("");
159
160   ns_info = _lookup_namespace (ns);
161   g_free (ns);
162
163   id = ++ns_info->attribute_id_counter;
164   attributes[ns_info->id] = g_realloc (attributes[ns_info->id], (id + 1) * sizeof (char *));
165   attributes[ns_info->id][id] = g_strdup (attribute);
166   
167   attr_id = MAKE_ATTR_ID (ns_info->id, id);
168
169   g_hash_table_insert (attribute_hash, attributes[ns_info->id][id], GUINT_TO_POINTER (attr_id));
170
171   return attr_id;
172 }
173
174 static void
175 ensure_attribute_hash (void)
176 {
177   if (attribute_hash != NULL)
178     return;
179
180   ns_hash = g_hash_table_new (g_str_hash, g_str_equal);
181   attribute_hash = g_hash_table_new (g_str_hash, g_str_equal);
182
183 #define REGISTER_ATTRIBUTE(name) G_STMT_START{\
184   guint _u = _lookup_attribute (G_FILE_ATTRIBUTE_ ## name); \
185   /* use for generating the ID: g_print ("#define G_FILE_ATTRIBUTE_ID_%s (%u + %u)\n", #name + 17, _u & ~ID_MASK, _u & ID_MASK); */ \
186   g_assert (_u == G_FILE_ATTRIBUTE_ID_ ## name); \
187 }G_STMT_END
188
189   REGISTER_ATTRIBUTE (STANDARD_TYPE);
190   REGISTER_ATTRIBUTE (STANDARD_IS_HIDDEN);
191   REGISTER_ATTRIBUTE (STANDARD_IS_BACKUP);
192   REGISTER_ATTRIBUTE (STANDARD_IS_SYMLINK);
193   REGISTER_ATTRIBUTE (STANDARD_IS_VIRTUAL);
194   REGISTER_ATTRIBUTE (STANDARD_NAME);
195   REGISTER_ATTRIBUTE (STANDARD_DISPLAY_NAME);
196   REGISTER_ATTRIBUTE (STANDARD_EDIT_NAME);
197   REGISTER_ATTRIBUTE (STANDARD_COPY_NAME);
198   REGISTER_ATTRIBUTE (STANDARD_DESCRIPTION);
199   REGISTER_ATTRIBUTE (STANDARD_ICON);
200   REGISTER_ATTRIBUTE (STANDARD_CONTENT_TYPE);
201   REGISTER_ATTRIBUTE (STANDARD_FAST_CONTENT_TYPE);
202   REGISTER_ATTRIBUTE (STANDARD_SIZE);
203   REGISTER_ATTRIBUTE (STANDARD_ALLOCATED_SIZE);
204   REGISTER_ATTRIBUTE (STANDARD_SYMLINK_TARGET);
205   REGISTER_ATTRIBUTE (STANDARD_TARGET_URI);
206   REGISTER_ATTRIBUTE (STANDARD_SORT_ORDER);
207   REGISTER_ATTRIBUTE (ETAG_VALUE);
208   REGISTER_ATTRIBUTE (ID_FILE);
209   REGISTER_ATTRIBUTE (ID_FILESYSTEM);
210   REGISTER_ATTRIBUTE (ACCESS_CAN_READ);
211   REGISTER_ATTRIBUTE (ACCESS_CAN_WRITE);
212   REGISTER_ATTRIBUTE (ACCESS_CAN_EXECUTE);
213   REGISTER_ATTRIBUTE (ACCESS_CAN_DELETE);
214   REGISTER_ATTRIBUTE (ACCESS_CAN_TRASH);
215   REGISTER_ATTRIBUTE (ACCESS_CAN_RENAME);
216   REGISTER_ATTRIBUTE (MOUNTABLE_CAN_MOUNT);
217   REGISTER_ATTRIBUTE (MOUNTABLE_CAN_UNMOUNT);
218   REGISTER_ATTRIBUTE (MOUNTABLE_CAN_EJECT);
219   REGISTER_ATTRIBUTE (MOUNTABLE_UNIX_DEVICE);
220   REGISTER_ATTRIBUTE (MOUNTABLE_UNIX_DEVICE_FILE);
221   REGISTER_ATTRIBUTE (MOUNTABLE_HAL_UDI);
222   REGISTER_ATTRIBUTE (MOUNTABLE_CAN_START);
223   REGISTER_ATTRIBUTE (MOUNTABLE_CAN_START_DEGRADED);
224   REGISTER_ATTRIBUTE (MOUNTABLE_CAN_STOP);
225   REGISTER_ATTRIBUTE (MOUNTABLE_START_STOP_TYPE);
226   REGISTER_ATTRIBUTE (MOUNTABLE_CAN_POLL);
227   REGISTER_ATTRIBUTE (MOUNTABLE_IS_MEDIA_CHECK_AUTOMATIC);
228   REGISTER_ATTRIBUTE (TIME_MODIFIED);
229   REGISTER_ATTRIBUTE (TIME_MODIFIED_USEC);
230   REGISTER_ATTRIBUTE (TIME_ACCESS);
231   REGISTER_ATTRIBUTE (TIME_ACCESS_USEC);
232   REGISTER_ATTRIBUTE (TIME_CHANGED);
233   REGISTER_ATTRIBUTE (TIME_CHANGED_USEC);
234   REGISTER_ATTRIBUTE (TIME_CREATED);
235   REGISTER_ATTRIBUTE (TIME_CREATED_USEC);
236   REGISTER_ATTRIBUTE (UNIX_DEVICE);
237   REGISTER_ATTRIBUTE (UNIX_INODE);
238   REGISTER_ATTRIBUTE (UNIX_MODE);
239   REGISTER_ATTRIBUTE (UNIX_NLINK);
240   REGISTER_ATTRIBUTE (UNIX_UID);
241   REGISTER_ATTRIBUTE (UNIX_GID);
242   REGISTER_ATTRIBUTE (UNIX_RDEV);
243   REGISTER_ATTRIBUTE (UNIX_BLOCK_SIZE);
244   REGISTER_ATTRIBUTE (UNIX_BLOCKS);
245   REGISTER_ATTRIBUTE (UNIX_IS_MOUNTPOINT);
246   REGISTER_ATTRIBUTE (DOS_IS_ARCHIVE);
247   REGISTER_ATTRIBUTE (DOS_IS_SYSTEM);
248   REGISTER_ATTRIBUTE (OWNER_USER);
249   REGISTER_ATTRIBUTE (OWNER_USER_REAL);
250   REGISTER_ATTRIBUTE (OWNER_GROUP);
251   REGISTER_ATTRIBUTE (THUMBNAIL_PATH);
252   REGISTER_ATTRIBUTE (THUMBNAILING_FAILED);
253   REGISTER_ATTRIBUTE (PREVIEW_ICON);
254   REGISTER_ATTRIBUTE (FILESYSTEM_SIZE);
255   REGISTER_ATTRIBUTE (FILESYSTEM_FREE);
256   REGISTER_ATTRIBUTE (FILESYSTEM_TYPE);
257   REGISTER_ATTRIBUTE (FILESYSTEM_READONLY);
258   REGISTER_ATTRIBUTE (FILESYSTEM_USE_PREVIEW);
259   REGISTER_ATTRIBUTE (GVFS_BACKEND);
260   REGISTER_ATTRIBUTE (SELINUX_CONTEXT);
261   REGISTER_ATTRIBUTE (TRASH_ITEM_COUNT);
262   REGISTER_ATTRIBUTE (TRASH_ORIG_PATH);
263   REGISTER_ATTRIBUTE (TRASH_DELETION_DATE);
264
265 #undef REGISTER_ATTRIBUTE
266 }
267
268 static guint32
269 lookup_namespace (const char *namespace)
270 {
271   NSInfo *ns_info;
272   guint32 id;
273   
274   G_LOCK (attribute_hash);
275   
276   ensure_attribute_hash ();
277
278   ns_info = _lookup_namespace (namespace);
279   id = 0;
280   if (ns_info)
281     id = ns_info->id;
282   
283   G_UNLOCK (attribute_hash);
284
285   return id;
286 }
287
288 static char *
289 get_attribute_for_id (int attribute)
290 {
291   char *s;
292   G_LOCK (attribute_hash);
293   s = attributes[GET_NS(attribute)][GET_ID(attribute)];
294   G_UNLOCK (attribute_hash);
295   return s;
296 }
297
298 static guint32
299 lookup_attribute (const char *attribute)
300 {
301   guint32 attr_id;
302   
303   G_LOCK (attribute_hash);
304   ensure_attribute_hash ();
305
306   attr_id = _lookup_attribute (attribute);
307   
308   G_UNLOCK (attribute_hash);
309   
310   return attr_id;
311 }
312
313 static void
314 g_file_info_finalize (GObject *object)
315 {
316   GFileInfo *info;
317   int i;
318   GFileAttribute *attrs;
319
320   info = G_FILE_INFO (object);
321
322   attrs = (GFileAttribute *)info->attributes->data;
323   for (i = 0; i < info->attributes->len; i++)
324     _g_file_attribute_value_clear (&attrs[i].value);
325   g_array_free (info->attributes, TRUE);
326
327   if (info->mask != NO_ATTRIBUTE_MASK)
328     g_file_attribute_matcher_unref (info->mask);
329
330   G_OBJECT_CLASS (g_file_info_parent_class)->finalize (object);
331 }
332
333 static void
334 g_file_info_class_init (GFileInfoClass *klass)
335 {
336   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
337   
338   gobject_class->finalize = g_file_info_finalize;
339 }
340
341 static void
342 g_file_info_init (GFileInfo *info)
343 {
344   info->mask = NO_ATTRIBUTE_MASK;
345   info->attributes = g_array_new (FALSE, FALSE,
346                                   sizeof (GFileAttribute));
347 }
348
349 /**
350  * g_file_info_new:
351  * 
352  * Creates a new file info structure.
353  * 
354  * Returns: a #GFileInfo.
355  **/
356 GFileInfo *
357 g_file_info_new (void)
358 {
359   return g_object_new (G_TYPE_FILE_INFO, NULL);
360 }
361
362 /**
363  * g_file_info_copy_into:
364  * @src_info: source to copy attributes from.
365  * @dest_info: destination to copy attributes to.
366  * 
367  * Copies all of the #GFileAttribute<!-- -->s from @src_info to @dest_info.
368  **/
369 void
370 g_file_info_copy_into (GFileInfo *src_info, 
371                        GFileInfo *dest_info)
372 {
373   GFileAttribute *source, *dest;
374   int i;
375
376   g_return_if_fail (G_IS_FILE_INFO (src_info));
377   g_return_if_fail (G_IS_FILE_INFO (dest_info));
378
379   dest = (GFileAttribute *)dest_info->attributes->data;
380   for (i = 0; i < dest_info->attributes->len; i++)
381     _g_file_attribute_value_clear (&dest[i].value);
382   
383   g_array_set_size (dest_info->attributes,
384                     src_info->attributes->len);
385
386   source = (GFileAttribute *)src_info->attributes->data;
387   dest = (GFileAttribute *)dest_info->attributes->data;
388   
389   for (i = 0; i < src_info->attributes->len; i++)
390     {
391       dest[i].attribute = source[i].attribute;
392       dest[i].value.type = G_FILE_ATTRIBUTE_TYPE_INVALID;
393       _g_file_attribute_value_set (&dest[i].value, &source[i].value);
394     }
395
396   if (dest_info->mask != NO_ATTRIBUTE_MASK)
397     g_file_attribute_matcher_unref (dest_info->mask);
398
399   if (src_info->mask == NO_ATTRIBUTE_MASK)
400     dest_info->mask = NO_ATTRIBUTE_MASK;
401   else
402     dest_info->mask = g_file_attribute_matcher_ref (src_info->mask);
403 }
404
405 /**
406  * g_file_info_dup:
407  * @other: a #GFileInfo.
408  * 
409  * Duplicates a file info structure.
410  * 
411  * Returns: a duplicate #GFileInfo of @other.
412  **/
413 GFileInfo *
414 g_file_info_dup (GFileInfo *other)
415 {
416   GFileInfo *new;
417   
418   g_return_val_if_fail (G_IS_FILE_INFO (other), NULL);
419   
420   new = g_file_info_new ();
421   g_file_info_copy_into (other, new);
422   return new;
423 }
424
425 /**
426  * g_file_info_set_attribute_mask:
427  * @info: a #GFileInfo.
428  * @mask: a #GFileAttributeMatcher.
429  *
430  * Sets @mask on @info to match specific attribute types.
431  **/
432 void
433 g_file_info_set_attribute_mask (GFileInfo             *info,
434                                 GFileAttributeMatcher *mask)
435 {
436   GFileAttribute *attr;
437   int i;
438   
439   g_return_if_fail (G_IS_FILE_INFO (info));
440   
441   if (mask != info->mask)
442     {
443       if (info->mask != NO_ATTRIBUTE_MASK)
444         g_file_attribute_matcher_unref (info->mask);
445       info->mask = g_file_attribute_matcher_ref (mask);
446
447       /* Remove non-matching attributes */
448       for (i = 0; i < info->attributes->len; i++)
449         {
450           attr = &g_array_index (info->attributes, GFileAttribute, i);
451           if (!_g_file_attribute_matcher_matches_id (mask,
452                                                     attr->attribute))
453             {
454               _g_file_attribute_value_clear (&attr->value);
455               g_array_remove_index (info->attributes, i);
456               i--;
457             }
458         }
459     }
460 }
461
462 /**
463  * g_file_info_unset_attribute_mask:
464  * @info: #GFileInfo.
465  * 
466  * Unsets a mask set by g_file_info_set_attribute_mask(), if one
467  * is set.
468  **/
469 void
470 g_file_info_unset_attribute_mask (GFileInfo *info)
471 {
472   g_return_if_fail (G_IS_FILE_INFO (info));
473
474   if (info->mask != NO_ATTRIBUTE_MASK)
475     g_file_attribute_matcher_unref (info->mask);
476   info->mask = NO_ATTRIBUTE_MASK;
477 }
478
479 /**
480  * g_file_info_clear_status:
481  * @info: a #GFileInfo.
482  *
483  * Clears the status information from @info.
484  **/
485 void
486 g_file_info_clear_status (GFileInfo  *info)
487 {
488   GFileAttribute *attrs;
489   int i;
490   
491   g_return_if_fail (G_IS_FILE_INFO (info));
492
493   attrs = (GFileAttribute *)info->attributes->data;
494   for (i = 0; i < info->attributes->len; i++)
495     attrs[i].value.status = G_FILE_ATTRIBUTE_STATUS_UNSET;
496 }
497
498 static int
499 g_file_info_find_place (GFileInfo  *info,
500                         guint32     attribute)
501 {
502   int min, max, med;
503   GFileAttribute *attrs;
504   /* Binary search for the place where attribute would be, if it's
505      in the array */
506
507   min = 0;
508   max = info->attributes->len;
509
510   attrs = (GFileAttribute *)info->attributes->data;
511
512   while (min < max)
513     {
514       med = min + (max - min) / 2;
515       if (attrs[med].attribute == attribute)
516         {
517           min = med;
518           break;
519         }
520       else if (attrs[med].attribute < attribute)
521         min = med + 1;
522       else /* attrs[med].attribute > attribute */
523         max = med;
524     }
525
526   return min;
527 }
528
529 static GFileAttributeValue *
530 g_file_info_find_value (GFileInfo *info,
531                         guint32    attr_id)
532 {
533   GFileAttribute *attrs;
534   int i;
535
536   i = g_file_info_find_place (info, attr_id);
537   attrs = (GFileAttribute *)info->attributes->data;
538   if (i < info->attributes->len &&
539       attrs[i].attribute == attr_id)
540     return &attrs[i].value;
541   
542   return NULL;
543 }
544
545 static GFileAttributeValue *
546 g_file_info_find_value_by_name (GFileInfo  *info,
547                                 const char *attribute)
548 {
549   guint32 attr_id;
550
551   attr_id = lookup_attribute (attribute);
552   return g_file_info_find_value (info, attr_id);
553 }
554
555 /**
556  * g_file_info_has_attribute:
557  * @info: a #GFileInfo.
558  * @attribute: a file attribute key.
559  * 
560  * Checks if a file info structure has an attribute named @attribute.
561  * 
562  * Returns: %TRUE if @Ginfo has an attribute named @attribute, 
563  *     %FALSE otherwise.
564  **/
565 gboolean
566 g_file_info_has_attribute (GFileInfo  *info,
567                            const char *attribute)
568 {
569   GFileAttributeValue *value;
570
571   g_return_val_if_fail (G_IS_FILE_INFO (info), FALSE);
572   g_return_val_if_fail (attribute != NULL && *attribute != '\0', FALSE);
573
574   value = g_file_info_find_value_by_name (info, attribute);
575   return value != NULL;
576 }
577
578 /**
579  * g_file_info_has_namespace:
580  * @info: a #GFileInfo.
581  * @name_space: a file attribute namespace.
582  *
583  * Checks if a file info structure has an attribute in the
584  * specified @name_space.
585  *
586  * Returns: %TRUE if @Ginfo has an attribute in @name_space,
587  *     %FALSE otherwise.
588  *
589  * Since: 2.22
590  **/
591 gboolean
592 g_file_info_has_namespace (GFileInfo  *info,
593                            const char *name_space)
594 {
595   GFileAttribute *attrs;
596   guint32 ns_id;
597   int i;
598
599   g_return_val_if_fail (G_IS_FILE_INFO (info), FALSE);
600   g_return_val_if_fail (name_space != NULL, FALSE);
601
602   ns_id = lookup_namespace (name_space);
603
604   attrs = (GFileAttribute *)info->attributes->data;
605   for (i = 0; i < info->attributes->len; i++)
606     {
607       if (GET_NS (attrs[i].attribute) == ns_id)
608         return TRUE;
609     }
610
611   return FALSE;
612 }
613
614 /**
615  * g_file_info_list_attributes:
616  * @info: a #GFileInfo.
617  * @name_space: a file attribute key's namespace.
618  * 
619  * Lists the file info structure's attributes.
620  * 
621  * Returns: a null-terminated array of strings of all of the 
622  * possible attribute types for the given @name_space, or 
623  * %NULL on error.
624  **/
625 char **
626 g_file_info_list_attributes (GFileInfo  *info,
627                              const char *name_space)
628 {
629   GPtrArray *names;
630   GFileAttribute *attrs;
631   guint32 attribute;
632   guint32 ns_id = (name_space) ? lookup_namespace (name_space) : 0;
633   int i;
634  
635   g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
636
637   names = g_ptr_array_new ();
638   attrs = (GFileAttribute *)info->attributes->data;
639   for (i = 0; i < info->attributes->len; i++)
640     {
641       attribute = attrs[i].attribute;
642       if (ns_id == 0 || GET_NS (attribute) == ns_id)
643         g_ptr_array_add (names, g_strdup (get_attribute_for_id (attribute)));
644     }
645
646   /* NULL terminate */
647   g_ptr_array_add (names, NULL);
648   
649   return (char **)g_ptr_array_free (names, FALSE);
650 }
651
652 /**
653  * g_file_info_get_attribute_type:
654  * @info: a #GFileInfo.
655  * @attribute: a file attribute key.
656  * 
657  * Gets the attribute type for an attribute key.
658  * 
659  * Returns: a #GFileAttributeType for the given @attribute, or 
660  * %G_FILE_ATTRIBUTE_TYPE_INVALID if the key is not set.
661  **/
662 GFileAttributeType
663 g_file_info_get_attribute_type (GFileInfo  *info,
664                                 const char *attribute)
665 {
666   GFileAttributeValue *value;
667   
668   g_return_val_if_fail (G_IS_FILE_INFO (info), G_FILE_ATTRIBUTE_TYPE_INVALID);
669   g_return_val_if_fail (attribute != NULL && *attribute != '\0', G_FILE_ATTRIBUTE_TYPE_INVALID);
670
671   value = g_file_info_find_value_by_name (info, attribute);
672   if (value)
673     return value->type;
674   else
675     return G_FILE_ATTRIBUTE_TYPE_INVALID;
676 }
677
678 /**
679  * g_file_info_remove_attribute:
680  * @info: a #GFileInfo.
681  * @attribute: a file attribute key.
682  * 
683  * Removes all cases of @attribute from @info if it exists.
684  **/
685 void
686 g_file_info_remove_attribute (GFileInfo  *info,
687                               const char *attribute)
688 {
689   guint32 attr_id;
690   GFileAttribute *attrs;
691   int i;
692
693   g_return_if_fail (G_IS_FILE_INFO (info));
694   g_return_if_fail (attribute != NULL && *attribute != '\0');
695
696   attr_id = lookup_attribute (attribute);
697   
698   i = g_file_info_find_place (info, attr_id);
699   attrs = (GFileAttribute *)info->attributes->data;
700   if (i < info->attributes->len &&
701       attrs[i].attribute == attr_id)
702     {
703       _g_file_attribute_value_clear (&attrs[i].value);
704       g_array_remove_index (info->attributes, i);
705     }
706 }
707
708 /**
709  * g_file_info_get_attribute_data:
710  * @info: a #GFileInfo
711  * @attribute: a file attribute key
712  * @type: return location for the attribute type, or %NULL
713  * @value_pp: return location for the attribute value, or %NULL
714  * @status: return location for the attribute status, or %NULL
715  *
716  * Gets the attribute type, value and status for an attribute key.
717  *
718  * Returns: %TRUE if @info has an attribute named @attribute, 
719  *      %FALSE otherwise.
720  */
721 gboolean
722 g_file_info_get_attribute_data (GFileInfo            *info,
723                                 const char           *attribute,
724                                 GFileAttributeType   *type,
725                                 gpointer             *value_pp,
726                                 GFileAttributeStatus *status)
727 {
728   GFileAttributeValue *value;
729
730   value = g_file_info_find_value_by_name (info, attribute);
731   if (value == NULL)
732     return FALSE;
733
734   if (status)
735     *status = value->status;
736
737   if (type)
738     *type = value->type;
739
740   if (value_pp)
741     *value_pp = _g_file_attribute_value_peek_as_pointer (value);
742   
743   return TRUE;
744 }
745
746 /** 
747  * g_file_info_get_attribute_status:
748  * @info: a #GFileInfo
749  * @attribute: a file attribute key
750  *
751  * Gets the attribute status for an attribute key.
752  *
753  * Returns: a #GFileAttributeStatus for the given @attribute, or 
754  *    %G_FILE_ATTRIBUTE_STATUS_UNSET if the key is invalid.
755  *
756  */
757 GFileAttributeStatus
758 g_file_info_get_attribute_status (GFileInfo  *info,
759                                   const char *attribute)
760 {
761   GFileAttributeValue *val;
762   
763   g_return_val_if_fail (G_IS_FILE_INFO (info), 0);
764   g_return_val_if_fail (attribute != NULL && *attribute != '\0', 0);
765
766   val = g_file_info_find_value_by_name (info, attribute);
767   if (val)
768     return val->status;
769
770   return G_FILE_ATTRIBUTE_STATUS_UNSET;
771 }
772
773 /**
774  * g_file_info_set_attribute_status:
775  * @info: a #GFileInfo
776  * @attribute: a file attribute key
777  * @status: a #GFileAttributeStatus
778  *
779  * Sets the attribute status for an attribute key. This is only
780  * needed by external code that implement g_file_set_attributes_from_info()
781  * or similar functions.
782  *
783  * The attribute must exist in @info for this to work. Otherwise %FALSE
784  * is returned and @info is unchanged.
785  *
786  * Returns: %TRUE if the status was changed, %FALSE if the key was not set.
787  *
788  * Since: 2.22
789  */
790 gboolean
791 g_file_info_set_attribute_status (GFileInfo  *info,
792                                   const char *attribute,
793                                   GFileAttributeStatus status)
794 {
795   GFileAttributeValue *val;
796
797   g_return_val_if_fail (G_IS_FILE_INFO (info), 0);
798   g_return_val_if_fail (attribute != NULL && *attribute != '\0', 0);
799
800   val = g_file_info_find_value_by_name (info, attribute);
801   if (val)
802     {
803       val->status = status;
804       return TRUE;
805     }
806
807   return FALSE;
808 }
809
810 GFileAttributeValue *
811 _g_file_info_get_attribute_value (GFileInfo  *info,
812                                   const char *attribute)
813   
814 {
815   g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
816   g_return_val_if_fail (attribute != NULL && *attribute != '\0', NULL);
817
818   return g_file_info_find_value_by_name (info, attribute);
819 }
820
821 /**
822  * g_file_info_get_attribute_as_string:
823  * @info: a #GFileInfo.
824  * @attribute: a file attribute key.
825  * 
826  * Gets the value of a attribute, formated as a string.
827  * This escapes things as needed to make the string valid
828  * utf8.
829  * 
830  * Returns: a UTF-8 string associated with the given @attribute.
831  *    When you're done with the string it must be freed with g_free().
832  **/
833 char *
834 g_file_info_get_attribute_as_string (GFileInfo  *info,
835                                      const char *attribute)
836 {
837   GFileAttributeValue *val;
838   val = _g_file_info_get_attribute_value (info, attribute);
839   if (val) 
840     return _g_file_attribute_value_as_string (val);
841   return NULL;
842 }
843
844
845 /**
846  * g_file_info_get_attribute_object:
847  * @info: a #GFileInfo.
848  * @attribute: a file attribute key.
849  * 
850  * Gets the value of a #GObject attribute. If the attribute does 
851  * not contain a #GObject, %NULL will be returned.
852  * 
853  * Returns: a #GObject associated with the given @attribute, or
854  * %NULL otherwise.
855  **/
856 GObject *
857 g_file_info_get_attribute_object (GFileInfo  *info,
858                                   const char *attribute)
859 {
860   GFileAttributeValue *value;
861   
862   g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
863   g_return_val_if_fail (attribute != NULL && *attribute != '\0', NULL);
864
865   value = g_file_info_find_value_by_name (info, attribute);
866   return _g_file_attribute_value_get_object (value);
867 }
868
869 /**
870  * g_file_info_get_attribute_string:
871  * @info: a #GFileInfo.
872  * @attribute: a file attribute key.
873  * 
874  * Gets the value of a string attribute. If the attribute does 
875  * not contain a string, %NULL will be returned.
876  * 
877  * Returns: the contents of the @attribute value as a string, or 
878  * %NULL otherwise.
879  **/
880 const char *
881 g_file_info_get_attribute_string (GFileInfo  *info,
882                                   const char *attribute)
883 {
884   GFileAttributeValue *value;
885   
886   g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
887   g_return_val_if_fail (attribute != NULL && *attribute != '\0', NULL);
888
889   value = g_file_info_find_value_by_name (info, attribute);
890   return _g_file_attribute_value_get_string (value);
891 }
892
893 /**
894  * g_file_info_get_attribute_byte_string:
895  * @info: a #GFileInfo.
896  * @attribute: a file attribute key.
897  * 
898  * Gets the value of a byte string attribute. If the attribute does 
899  * not contain a byte string, %NULL will be returned.
900  * 
901  * Returns: the contents of the @attribute value as a byte string, or 
902  * %NULL otherwise.
903  **/
904 const char *
905 g_file_info_get_attribute_byte_string (GFileInfo  *info,
906                                        const char *attribute)
907 {
908   GFileAttributeValue *value;
909   
910   g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
911   g_return_val_if_fail (attribute != NULL && *attribute != '\0', NULL);
912
913   value = g_file_info_find_value_by_name (info, attribute);
914   return _g_file_attribute_value_get_byte_string (value);
915 }
916
917 /**
918  * g_file_info_get_attribute_stringv:
919  * @info: a #GFileInfo.
920  * @attribute: a file attribute key.
921  *
922  * Gets the value of a stringv attribute. If the attribute does
923  * not contain a stringv, %NULL will be returned.
924  *
925  * Returns: the contents of the @attribute value as a stringv, or
926  * %NULL otherwise. Do not free.
927  *
928  * Since: 2.22
929  **/
930 char **
931 g_file_info_get_attribute_stringv (GFileInfo  *info,
932                                    const char *attribute)
933 {
934   GFileAttributeValue *value;
935
936   g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
937   g_return_val_if_fail (attribute != NULL && *attribute != '\0', NULL);
938
939   value = g_file_info_find_value_by_name (info, attribute);
940   return _g_file_attribute_value_get_stringv (value);
941 }
942
943 /**
944  * g_file_info_get_attribute_boolean:
945  * @info: a #GFileInfo.
946  * @attribute: a file attribute key.
947  * 
948  * Gets the value of a boolean attribute. If the attribute does not
949  * contain a boolean value, %FALSE will be returned.
950  * 
951  * Returns: the boolean value contained within the attribute. 
952  **/
953 gboolean
954 g_file_info_get_attribute_boolean (GFileInfo  *info,
955                                    const char *attribute)
956 {
957   GFileAttributeValue *value;
958   
959   g_return_val_if_fail (G_IS_FILE_INFO (info), FALSE);
960   g_return_val_if_fail (attribute != NULL && *attribute != '\0', FALSE);
961
962   value = g_file_info_find_value_by_name (info, attribute);
963   return _g_file_attribute_value_get_boolean (value);
964 }
965
966 /**
967  * g_file_info_get_attribute_uint32:
968  * @info: a #GFileInfo.
969  * @attribute: a file attribute key.
970  * 
971  * Gets an unsigned 32-bit integer contained within the attribute. If the 
972  * attribute does not contain an unsigned 32-bit integer, or is invalid, 
973  * 0 will be returned.
974  * 
975  * Returns: an unsigned 32-bit integer from the attribute. 
976  **/
977 guint32
978 g_file_info_get_attribute_uint32 (GFileInfo  *info,
979                                   const char *attribute)
980 {
981   GFileAttributeValue *value;
982   
983   g_return_val_if_fail (G_IS_FILE_INFO (info), 0);
984   g_return_val_if_fail (attribute != NULL && *attribute != '\0', 0);
985
986   value = g_file_info_find_value_by_name (info, attribute);
987   return _g_file_attribute_value_get_uint32 (value);
988 }
989
990 /**
991  * g_file_info_get_attribute_int32:
992  * @info: a #GFileInfo.
993  * @attribute: a file attribute key.
994  * 
995  * Gets a signed 32-bit integer contained within the attribute. If the 
996  * attribute does not contain a signed 32-bit integer, or is invalid, 
997  * 0 will be returned.
998  * 
999  * Returns: a signed 32-bit integer from the attribute.
1000  **/
1001 gint32
1002 g_file_info_get_attribute_int32 (GFileInfo  *info,
1003                                  const char *attribute)
1004 {
1005   GFileAttributeValue *value;
1006
1007   g_return_val_if_fail (G_IS_FILE_INFO (info), 0);
1008   g_return_val_if_fail (attribute != NULL && *attribute != '\0', 0);
1009
1010   value = g_file_info_find_value_by_name (info, attribute);
1011   return _g_file_attribute_value_get_int32 (value);
1012 }
1013
1014 /**
1015  * g_file_info_get_attribute_uint64:
1016  * @info: a #GFileInfo.
1017  * @attribute: a file attribute key.
1018  * 
1019  * Gets a unsigned 64-bit integer contained within the attribute. If the 
1020  * attribute does not contain an unsigned 64-bit integer, or is invalid, 
1021  * 0 will be returned.
1022  * 
1023  * Returns: a unsigned 64-bit integer from the attribute. 
1024  **/
1025 guint64
1026 g_file_info_get_attribute_uint64 (GFileInfo  *info,
1027                                   const char *attribute)
1028 {
1029   GFileAttributeValue *value;
1030
1031   g_return_val_if_fail (G_IS_FILE_INFO (info), 0);
1032   g_return_val_if_fail (attribute != NULL && *attribute != '\0', 0);
1033
1034   value = g_file_info_find_value_by_name (info, attribute);
1035   return _g_file_attribute_value_get_uint64 (value);
1036 }
1037
1038 /**
1039  * g_file_info_get_attribute_int64:
1040  * @info: a #GFileInfo.
1041  * @attribute: a file attribute key.
1042  * 
1043  * Gets a signed 64-bit integer contained within the attribute. If the 
1044  * attribute does not contain an signed 64-bit integer, or is invalid, 
1045  * 0 will be returned.
1046  * 
1047  * Returns: a signed 64-bit integer from the attribute. 
1048  **/
1049 gint64
1050 g_file_info_get_attribute_int64  (GFileInfo  *info,
1051                                   const char *attribute)
1052 {
1053   GFileAttributeValue *value;
1054
1055   g_return_val_if_fail (G_IS_FILE_INFO (info), 0);
1056   g_return_val_if_fail (attribute != NULL && *attribute != '\0', 0);
1057
1058   value = g_file_info_find_value_by_name (info, attribute);
1059   return _g_file_attribute_value_get_int64 (value);
1060 }
1061
1062 static GFileAttributeValue *
1063 g_file_info_create_value (GFileInfo *info,
1064                           guint32 attr_id)
1065 {
1066   GFileAttribute *attrs;
1067   int i;
1068
1069   if (info->mask != NO_ATTRIBUTE_MASK &&
1070       !_g_file_attribute_matcher_matches_id (info->mask, attr_id))
1071     return NULL;
1072   
1073   i = g_file_info_find_place (info, attr_id);
1074   
1075   attrs = (GFileAttribute *)info->attributes->data;
1076   if (i < info->attributes->len &&
1077       attrs[i].attribute == attr_id)
1078     return &attrs[i].value;
1079   else
1080     {
1081       GFileAttribute attr = { 0 };
1082       attr.attribute = attr_id;
1083       g_array_insert_val (info->attributes, i, attr);
1084
1085       attrs = (GFileAttribute *)info->attributes->data;
1086       return &attrs[i].value;
1087     }
1088 }
1089
1090 void
1091 _g_file_info_set_attribute_by_id (GFileInfo                 *info,
1092                                   guint32                    attribute,
1093                                   GFileAttributeType         type,
1094                                   gpointer                   value_p)
1095 {
1096   GFileAttributeValue *value;
1097
1098   value = g_file_info_create_value (info, attribute);
1099
1100   if (value)
1101     _g_file_attribute_value_set_from_pointer (value, type, value_p, TRUE);
1102 }
1103
1104 /**
1105  * g_file_info_set_attribute:
1106  * @info: a #GFileInfo.
1107  * @attribute: a file attribute key.
1108  * @type: a #GFileAttributeType
1109  * @value_p: pointer to the value
1110  * 
1111  * Sets the @attribute to contain the given value, if possible.
1112  **/
1113 void
1114 g_file_info_set_attribute (GFileInfo                 *info,
1115                            const char                *attribute,
1116                            GFileAttributeType         type,
1117                            gpointer                   value_p)
1118 {
1119   g_return_if_fail (G_IS_FILE_INFO (info));
1120   g_return_if_fail (attribute != NULL && *attribute != '\0');
1121
1122   _g_file_info_set_attribute_by_id (info, lookup_attribute (attribute), type, value_p);
1123 }
1124
1125 void
1126 _g_file_info_set_attribute_object_by_id (GFileInfo *info,
1127                                          guint32    attribute,
1128                                          GObject   *attr_value)
1129 {
1130   GFileAttributeValue *value;
1131
1132   value = g_file_info_create_value (info, attribute);
1133   if (value)
1134     _g_file_attribute_value_set_object (value, attr_value);
1135 }
1136
1137 /**
1138  * g_file_info_set_attribute_object:
1139  * @info: a #GFileInfo.
1140  * @attribute: a file attribute key.
1141  * @attr_value: a #GObject.
1142  * 
1143  * Sets the @attribute to contain the given @attr_value, 
1144  * if possible.
1145  **/
1146 void
1147 g_file_info_set_attribute_object (GFileInfo  *info,
1148                                   const char *attribute,
1149                                   GObject    *attr_value)
1150 {
1151   g_return_if_fail (G_IS_FILE_INFO (info));
1152   g_return_if_fail (attribute != NULL && *attribute != '\0');
1153   g_return_if_fail (G_IS_OBJECT (attr_value));
1154
1155   _g_file_info_set_attribute_object_by_id (info,
1156                                            lookup_attribute (attribute),
1157                                            attr_value);
1158 }
1159
1160 void
1161 _g_file_info_set_attribute_stringv_by_id (GFileInfo *info,
1162                                           guint32    attribute,
1163                                           char     **attr_value)
1164 {
1165   GFileAttributeValue *value;
1166
1167   value = g_file_info_create_value (info, attribute);
1168   if (value)
1169     _g_file_attribute_value_set_stringv (value, attr_value);
1170 }
1171
1172 /**
1173  * g_file_info_set_attribute_stringv:
1174  * @info: a #GFileInfo.
1175  * @attribute: a file attribute key.
1176  * @attr_value: a %NULL terminated string array
1177  *
1178  * Sets the @attribute to contain the given @attr_value,
1179  * if possible.
1180  *
1181  * Sinze: 2.22
1182  **/
1183 void
1184 g_file_info_set_attribute_stringv (GFileInfo  *info,
1185                                    const char *attribute,
1186                                    char      **attr_value)
1187 {
1188   g_return_if_fail (G_IS_FILE_INFO (info));
1189   g_return_if_fail (attribute != NULL && *attribute != '\0');
1190   g_return_if_fail (attr_value != NULL);
1191
1192   _g_file_info_set_attribute_stringv_by_id (info, 
1193                                             lookup_attribute (attribute),
1194                                             attr_value);
1195 }
1196
1197 void
1198 _g_file_info_set_attribute_string_by_id (GFileInfo  *info,
1199                                          guint32     attribute,
1200                                          const char *attr_value)
1201 {
1202   GFileAttributeValue *value;
1203
1204   value = g_file_info_create_value (info, attribute);
1205   if (value)
1206     _g_file_attribute_value_set_string (value, attr_value);
1207 }
1208
1209 /**
1210  * g_file_info_set_attribute_string:
1211  * @info: a #GFileInfo.
1212  * @attribute: a file attribute key.
1213  * @attr_value: a string.
1214  * 
1215  * Sets the @attribute to contain the given @attr_value, 
1216  * if possible.
1217  **/
1218 void
1219 g_file_info_set_attribute_string (GFileInfo  *info,
1220                                   const char *attribute,
1221                                   const char *attr_value)
1222 {
1223   g_return_if_fail (G_IS_FILE_INFO (info));
1224   g_return_if_fail (attribute != NULL && *attribute != '\0');
1225   g_return_if_fail (attr_value != NULL);
1226
1227   _g_file_info_set_attribute_string_by_id (info,
1228                                            lookup_attribute (attribute),
1229                                            attr_value);
1230 }
1231
1232 void
1233 _g_file_info_set_attribute_byte_string_by_id (GFileInfo  *info,
1234                                               guint32     attribute,
1235                                               const char *attr_value)
1236 {
1237   GFileAttributeValue *value;
1238
1239   value = g_file_info_create_value (info, attribute);
1240   if (value)
1241     _g_file_attribute_value_set_byte_string (value, attr_value);
1242 }
1243
1244 /**
1245  * g_file_info_set_attribute_byte_string:
1246  * @info: a #GFileInfo.
1247  * @attribute: a file attribute key.
1248  * @attr_value: a byte string.
1249  * 
1250  * Sets the @attribute to contain the given @attr_value, 
1251  * if possible.
1252  **/
1253 void
1254 g_file_info_set_attribute_byte_string (GFileInfo  *info,
1255                                        const char *attribute,
1256                                        const char *attr_value)
1257 {
1258   g_return_if_fail (G_IS_FILE_INFO (info));
1259   g_return_if_fail (attribute != NULL && *attribute != '\0');
1260   g_return_if_fail (attr_value != NULL);
1261
1262   _g_file_info_set_attribute_byte_string_by_id (info,
1263                                                 lookup_attribute (attribute),
1264                                                 attr_value);
1265 }
1266
1267 void
1268 _g_file_info_set_attribute_boolean_by_id (GFileInfo *info,
1269                                           guint32    attribute,
1270                                           gboolean   attr_value)
1271 {
1272   GFileAttributeValue *value;
1273
1274   value = g_file_info_create_value (info, attribute);
1275   if (value)
1276     _g_file_attribute_value_set_boolean (value, attr_value);
1277 }
1278
1279 /**
1280  * g_file_info_set_attribute_boolean:
1281  * @info: a #GFileInfo.
1282  * @attribute: a file attribute key.
1283  * @attr_value: a boolean value.
1284  * 
1285  * Sets the @attribute to contain the given @attr_value, 
1286  * if possible.
1287  **/
1288 void
1289 g_file_info_set_attribute_boolean (GFileInfo  *info,
1290                                    const char *attribute,
1291                                    gboolean    attr_value)
1292 {
1293   g_return_if_fail (G_IS_FILE_INFO (info));
1294   g_return_if_fail (attribute != NULL && *attribute != '\0');
1295
1296   _g_file_info_set_attribute_boolean_by_id (info,
1297                                             lookup_attribute (attribute),
1298                                             attr_value);
1299 }
1300
1301 void
1302 _g_file_info_set_attribute_uint32_by_id (GFileInfo *info,
1303                                          guint32    attribute,
1304                                          guint32    attr_value)
1305 {
1306   GFileAttributeValue *value;
1307
1308   value = g_file_info_create_value (info, attribute);
1309   if (value)
1310     _g_file_attribute_value_set_uint32 (value, attr_value);
1311 }
1312
1313 /**
1314  * g_file_info_set_attribute_uint32:
1315  * @info: a #GFileInfo.
1316  * @attribute: a file attribute key.
1317  * @attr_value: an unsigned 32-bit integer.
1318  * 
1319  * Sets the @attribute to contain the given @attr_value, 
1320  * if possible.
1321  **/
1322 void
1323 g_file_info_set_attribute_uint32 (GFileInfo  *info,
1324                                   const char *attribute,
1325                                   guint32     attr_value)
1326 {
1327   g_return_if_fail (G_IS_FILE_INFO (info));
1328   g_return_if_fail (attribute != NULL && *attribute != '\0');
1329
1330   _g_file_info_set_attribute_uint32_by_id (info,
1331                                            lookup_attribute (attribute),
1332                                            attr_value);
1333 }
1334
1335 void
1336 _g_file_info_set_attribute_int32_by_id (GFileInfo *info,
1337                                         guint32    attribute,
1338                                         gint32     attr_value)
1339 {
1340   GFileAttributeValue *value;
1341
1342   value = g_file_info_create_value (info, attribute);
1343   if (value)
1344     _g_file_attribute_value_set_int32 (value, attr_value);
1345 }
1346
1347 /**
1348  * g_file_info_set_attribute_int32:
1349  * @info: a #GFileInfo.
1350  * @attribute: a file attribute key.
1351  * @attr_value: a signed 32-bit integer
1352  * 
1353  * Sets the @attribute to contain the given @attr_value, 
1354  * if possible.
1355  **/
1356 void
1357 g_file_info_set_attribute_int32 (GFileInfo  *info,
1358                                  const char *attribute,
1359                                  gint32      attr_value)
1360 {
1361   g_return_if_fail (G_IS_FILE_INFO (info));
1362   g_return_if_fail (attribute != NULL && *attribute != '\0');
1363
1364   _g_file_info_set_attribute_int32_by_id (info,
1365                                           lookup_attribute (attribute),
1366                                           attr_value);
1367 }
1368
1369 void
1370 _g_file_info_set_attribute_uint64_by_id (GFileInfo *info,
1371                                          guint32    attribute,
1372                                          guint64    attr_value)
1373 {
1374   GFileAttributeValue *value;
1375
1376   value = g_file_info_create_value (info, attribute);
1377   if (value)
1378     _g_file_attribute_value_set_uint64 (value, attr_value);
1379 }
1380
1381 /**
1382  * g_file_info_set_attribute_uint64:
1383  * @info: a #GFileInfo.
1384  * @attribute: a file attribute key.
1385  * @attr_value: an unsigned 64-bit integer.
1386  * 
1387  * Sets the @attribute to contain the given @attr_value, 
1388  * if possible.
1389  **/
1390 void
1391 g_file_info_set_attribute_uint64 (GFileInfo  *info,
1392                                   const char *attribute,
1393                                   guint64     attr_value)
1394 {
1395   g_return_if_fail (G_IS_FILE_INFO (info));
1396   g_return_if_fail (attribute != NULL && *attribute != '\0');
1397
1398   _g_file_info_set_attribute_uint64_by_id (info,
1399                                            lookup_attribute (attribute),
1400                                            attr_value);
1401 }
1402
1403 void
1404 _g_file_info_set_attribute_int64_by_id (GFileInfo *info,
1405                                         guint32    attribute,
1406                                         gint64     attr_value)
1407 {
1408   GFileAttributeValue *value;
1409
1410   value = g_file_info_create_value (info, attribute);
1411   if (value)
1412     _g_file_attribute_value_set_int64 (value, attr_value);
1413 }
1414
1415 /**
1416  * g_file_info_set_attribute_int64:
1417  * @info: a #GFileInfo.
1418  * @attribute: attribute name to set.
1419  * @attr_value: int64 value to set attribute to.
1420  * 
1421  * Sets the @attribute to contain the given @attr_value, 
1422  * if possible.
1423  * 
1424  **/
1425 void
1426 g_file_info_set_attribute_int64  (GFileInfo  *info,
1427                                   const char *attribute,
1428                                   gint64      attr_value)
1429 {
1430   g_return_if_fail (G_IS_FILE_INFO (info));
1431   g_return_if_fail (attribute != NULL && *attribute != '\0');
1432
1433   _g_file_info_set_attribute_int64_by_id (info,
1434                                           lookup_attribute (attribute),
1435                                           attr_value);
1436 }
1437
1438 /* Helper getters */
1439 /**
1440  * g_file_info_get_file_type:
1441  * @info: a #GFileInfo.
1442  * 
1443  * Gets a file's type (whether it is a regular file, symlink, etc). 
1444  * This is different from the file's content type, see g_file_info_get_content_type().
1445  * 
1446  * Returns: a #GFileType for the given file.
1447  **/
1448 GFileType
1449 g_file_info_get_file_type (GFileInfo *info)
1450 {
1451   static guint32 attr = 0;
1452   GFileAttributeValue *value;
1453
1454   g_return_val_if_fail (G_IS_FILE_INFO (info), G_FILE_TYPE_UNKNOWN);
1455   
1456   if (attr == 0)
1457     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_TYPE);
1458   
1459   value = g_file_info_find_value (info, attr);
1460   return (GFileType)_g_file_attribute_value_get_uint32 (value);
1461 }
1462
1463 /**
1464  * g_file_info_get_is_hidden:
1465  * @info: a #GFileInfo.
1466  * 
1467  * Checks if a file is hidden.
1468  * 
1469  * Returns: %TRUE if the file is a hidden file, %FALSE otherwise.
1470  **/
1471 gboolean
1472 g_file_info_get_is_hidden (GFileInfo *info)
1473 {
1474   static guint32 attr = 0;
1475   GFileAttributeValue *value;
1476   
1477   g_return_val_if_fail (G_IS_FILE_INFO (info), FALSE);
1478   
1479   if (attr == 0)
1480     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN);
1481   
1482   value = g_file_info_find_value (info, attr);
1483   return (GFileType)_g_file_attribute_value_get_boolean (value);
1484 }
1485
1486 /**
1487  * g_file_info_get_is_backup:
1488  * @info: a #GFileInfo.
1489  * 
1490  * Checks if a file is a backup file.
1491  * 
1492  * Returns: %TRUE if file is a backup file, %FALSE otherwise.
1493  **/
1494 gboolean
1495 g_file_info_get_is_backup (GFileInfo *info)
1496 {
1497   static guint32 attr = 0;
1498   GFileAttributeValue *value;
1499   
1500   g_return_val_if_fail (G_IS_FILE_INFO (info), FALSE);
1501   
1502   if (attr == 0)
1503     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_IS_BACKUP);
1504   
1505   value = g_file_info_find_value (info, attr);
1506   return (GFileType)_g_file_attribute_value_get_boolean (value);
1507 }
1508
1509 /**
1510  * g_file_info_get_is_symlink:
1511  * @info: a #GFileInfo.
1512  * 
1513  * Checks if a file is a symlink.
1514  * 
1515  * Returns: %TRUE if the given @info is a symlink.
1516  **/
1517 gboolean
1518 g_file_info_get_is_symlink (GFileInfo *info)
1519 {
1520   static guint32 attr = 0;
1521   GFileAttributeValue *value;
1522   
1523   g_return_val_if_fail (G_IS_FILE_INFO (info), FALSE);
1524   
1525   if (attr == 0)
1526     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK);
1527   
1528   value = g_file_info_find_value (info, attr);
1529   return (GFileType)_g_file_attribute_value_get_boolean (value);
1530 }
1531
1532 /**
1533  * g_file_info_get_name:
1534  * @info: a #GFileInfo.
1535  * 
1536  * Gets the name for a file.
1537  * 
1538  * Returns: a string containing the file name.
1539  **/
1540 const char *
1541 g_file_info_get_name (GFileInfo *info)
1542 {
1543   static guint32 attr = 0;
1544   GFileAttributeValue *value;
1545   
1546   g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
1547   
1548   if (attr == 0)
1549     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_NAME);
1550   
1551   value = g_file_info_find_value (info, attr);
1552   return _g_file_attribute_value_get_byte_string (value);
1553 }
1554
1555 /**
1556  * g_file_info_get_display_name:
1557  * @info: a #GFileInfo.
1558  * 
1559  * Gets a display name for a file.
1560  * 
1561  * Returns: a string containing the display name.
1562  **/
1563 const char *
1564 g_file_info_get_display_name (GFileInfo *info)
1565 {
1566   static guint32 attr = 0;
1567   GFileAttributeValue *value;
1568   
1569   g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
1570   
1571   if (attr == 0)
1572     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME);
1573   
1574   value = g_file_info_find_value (info, attr);
1575   return _g_file_attribute_value_get_string (value);
1576 }
1577
1578 /**
1579  * g_file_info_get_edit_name:
1580  * @info: a #GFileInfo.
1581  * 
1582  * Gets the edit name for a file.
1583  * 
1584  * Returns: a string containing the edit name.
1585  **/
1586 const char *
1587 g_file_info_get_edit_name (GFileInfo *info)
1588 {
1589   static guint32 attr = 0;
1590   GFileAttributeValue *value;
1591   
1592   g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
1593   
1594   if (attr == 0)
1595     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_EDIT_NAME);
1596   
1597   value = g_file_info_find_value (info, attr);
1598   return _g_file_attribute_value_get_string (value);
1599 }
1600
1601 /**
1602  * g_file_info_get_icon:
1603  * @info: a #GFileInfo.
1604  * 
1605  * Gets the icon for a file.
1606  * 
1607  * Returns: #GIcon for the given @info.
1608  **/
1609 GIcon *
1610 g_file_info_get_icon (GFileInfo *info)
1611 {
1612   static guint32 attr = 0;
1613   GFileAttributeValue *value;
1614   GObject *obj;
1615   
1616   g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
1617   
1618   if (attr == 0)
1619     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_ICON);
1620   
1621   value = g_file_info_find_value (info, attr);
1622   obj = _g_file_attribute_value_get_object (value);
1623   if (G_IS_ICON (obj))
1624     return G_ICON (obj);
1625   return NULL;
1626 }
1627
1628 /**
1629  * g_file_info_get_content_type:
1630  * @info: a #GFileInfo.
1631  * 
1632  * Gets the file's content type.
1633  * 
1634  * Returns: a string containing the file's content type.
1635  **/
1636 const char *
1637 g_file_info_get_content_type (GFileInfo *info)
1638 {
1639   static guint32 attr = 0;
1640   GFileAttributeValue *value;
1641   
1642   g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
1643   
1644   if (attr == 0)
1645     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE);
1646   
1647   value = g_file_info_find_value (info, attr);
1648   return _g_file_attribute_value_get_string (value);
1649 }
1650
1651 /**
1652  * g_file_info_get_size:
1653  * @info: a #GFileInfo.
1654  * 
1655  * Gets the file's size.
1656  * 
1657  * Returns: a #goffset containing the file's size. 
1658  **/
1659 goffset
1660 g_file_info_get_size (GFileInfo *info)
1661 {
1662   static guint32 attr = 0;
1663   GFileAttributeValue *value;
1664  
1665   g_return_val_if_fail (G_IS_FILE_INFO (info), (goffset) 0);
1666   
1667   if (attr == 0)
1668     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_SIZE);
1669   
1670   value = g_file_info_find_value (info, attr);
1671   return (goffset) _g_file_attribute_value_get_uint64 (value);
1672 }
1673
1674 /**
1675  * g_file_info_get_modification_time:
1676  * @info: a #GFileInfo.
1677  * @result: a #GTimeVal.
1678  * 
1679  * Gets the modification time of the current @info and sets it
1680  * in @result.
1681  **/
1682 void
1683 g_file_info_get_modification_time (GFileInfo *info,
1684                                    GTimeVal  *result)
1685 {
1686   static guint32 attr_mtime = 0, attr_mtime_usec;
1687   GFileAttributeValue *value;
1688
1689   g_return_if_fail (G_IS_FILE_INFO (info));
1690   g_return_if_fail (result != NULL);
1691   
1692   if (attr_mtime == 0)
1693     {
1694       attr_mtime = lookup_attribute (G_FILE_ATTRIBUTE_TIME_MODIFIED);
1695       attr_mtime_usec = lookup_attribute (G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC);
1696     }
1697   
1698   value = g_file_info_find_value (info, attr_mtime);
1699   result->tv_sec = _g_file_attribute_value_get_uint64 (value);
1700   value = g_file_info_find_value (info, attr_mtime_usec);
1701   result->tv_usec = _g_file_attribute_value_get_uint32 (value);
1702 }
1703
1704 /**
1705  * g_file_info_get_symlink_target:
1706  * @info: a #GFileInfo.
1707  * 
1708  * Gets the symlink target for a given #GFileInfo.
1709  * 
1710  * Returns: a string containing the symlink target.
1711  **/
1712 const char *
1713 g_file_info_get_symlink_target (GFileInfo *info)
1714 {
1715   static guint32 attr = 0;
1716   GFileAttributeValue *value;
1717   
1718   g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
1719   
1720   if (attr == 0)
1721     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET);
1722   
1723   value = g_file_info_find_value (info, attr);
1724   return _g_file_attribute_value_get_byte_string (value);
1725 }
1726
1727 /**
1728  * g_file_info_get_etag:
1729  * @info: a #GFileInfo.
1730  * 
1731  * Gets the <link linkend="gfile-etag">entity tag</link> for a given 
1732  * #GFileInfo. See %G_FILE_ATTRIBUTE_ETAG_VALUE.
1733  * 
1734  * Returns: a string containing the value of the "etag:value" attribute.
1735  **/
1736 const char *
1737 g_file_info_get_etag (GFileInfo *info)
1738 {
1739   static guint32 attr = 0;
1740   GFileAttributeValue *value;
1741   
1742   g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
1743   
1744   if (attr == 0)
1745     attr = lookup_attribute (G_FILE_ATTRIBUTE_ETAG_VALUE);
1746   
1747   value = g_file_info_find_value (info, attr);
1748   return _g_file_attribute_value_get_string (value);
1749 }
1750
1751 /**
1752  * g_file_info_get_sort_order:
1753  * @info: a #GFileInfo.
1754  * 
1755  * Gets the value of the sort_order attribute from the #GFileInfo.
1756  * See %G_FILE_ATTRIBUTE_STANDARD_SORT_ORDER.
1757  * 
1758  * Returns: a #gint32 containing the value of the "standard::sort_order" attribute.
1759  **/
1760 gint32
1761 g_file_info_get_sort_order (GFileInfo *info)
1762 {
1763   static guint32 attr = 0;
1764   GFileAttributeValue *value;
1765   
1766   g_return_val_if_fail (G_IS_FILE_INFO (info), 0);
1767   
1768   if (attr == 0)
1769     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_SORT_ORDER);
1770   
1771   value = g_file_info_find_value (info, attr);
1772   return _g_file_attribute_value_get_int32 (value);
1773 }
1774
1775 /* Helper setters: */
1776 /**
1777  * g_file_info_set_file_type:
1778  * @info: a #GFileInfo.
1779  * @type: a #GFileType.
1780  * 
1781  * Sets the file type in a #GFileInfo to @type.
1782  * See %G_FILE_ATTRIBUTE_STANDARD_TYPE.
1783  **/
1784 void
1785 g_file_info_set_file_type (GFileInfo *info,
1786                            GFileType  type)
1787 {
1788   static guint32 attr = 0;
1789   GFileAttributeValue *value;
1790   
1791   g_return_if_fail (G_IS_FILE_INFO (info));
1792   
1793   if (attr == 0)
1794     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_TYPE);
1795   
1796   value = g_file_info_create_value (info, attr);
1797   if (value)
1798     _g_file_attribute_value_set_uint32 (value, type);
1799 }
1800
1801 /**
1802  * g_file_info_set_is_hidden:
1803  * @info: a #GFileInfo.
1804  * @is_hidden: a #gboolean.
1805  * 
1806  * Sets the "is_hidden" attribute in a #GFileInfo according to @is_symlink.
1807  * See %G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN.
1808  **/
1809 void
1810 g_file_info_set_is_hidden (GFileInfo *info,
1811                            gboolean   is_hidden)
1812 {
1813   static guint32 attr = 0;
1814   GFileAttributeValue *value;
1815   
1816   g_return_if_fail (G_IS_FILE_INFO (info));
1817   
1818   if (attr == 0)
1819     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN);
1820   
1821   value = g_file_info_create_value (info, attr);
1822   if (value)
1823     _g_file_attribute_value_set_boolean (value, is_hidden);
1824 }
1825
1826 /**
1827  * g_file_info_set_is_symlink:
1828  * @info: a #GFileInfo.
1829  * @is_symlink: a #gboolean.
1830  * 
1831  * Sets the "is_symlink" attribute in a #GFileInfo according to @is_symlink.
1832  * See %G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK.
1833  **/
1834 void
1835 g_file_info_set_is_symlink (GFileInfo *info,
1836                             gboolean   is_symlink)
1837 {
1838   static guint32 attr = 0;
1839   GFileAttributeValue *value;
1840   
1841   g_return_if_fail (G_IS_FILE_INFO (info));
1842   
1843   if (attr == 0)
1844     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK);
1845   
1846   value = g_file_info_create_value (info, attr);
1847   if (value)
1848     _g_file_attribute_value_set_boolean (value, is_symlink);
1849 }
1850
1851 /**
1852  * g_file_info_set_name:
1853  * @info: a #GFileInfo.
1854  * @name: a string containing a name.
1855  * 
1856  * Sets the name attribute for the current #GFileInfo. 
1857  * See %G_FILE_ATTRIBUTE_STANDARD_NAME.
1858  **/
1859 void
1860 g_file_info_set_name (GFileInfo  *info,
1861                       const char *name)
1862 {
1863   static guint32 attr = 0;
1864   GFileAttributeValue *value;
1865   
1866   g_return_if_fail (G_IS_FILE_INFO (info));
1867   g_return_if_fail (name != NULL);
1868   
1869   if (attr == 0)
1870     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_NAME);
1871   
1872   value = g_file_info_create_value (info, attr);
1873   if (value)
1874     _g_file_attribute_value_set_byte_string (value, name);
1875 }
1876
1877 /**
1878  * g_file_info_set_display_name:
1879  * @info: a #GFileInfo.
1880  * @display_name: a string containing a display name.
1881  * 
1882  * Sets the display name for the current #GFileInfo.
1883  * See %G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME.
1884  **/
1885 void
1886 g_file_info_set_display_name (GFileInfo  *info,
1887                               const char *display_name)
1888 {
1889   static guint32 attr = 0;
1890   GFileAttributeValue *value;
1891   
1892   g_return_if_fail (G_IS_FILE_INFO (info));
1893   g_return_if_fail (display_name != NULL);
1894   
1895   if (attr == 0)
1896     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME);
1897   
1898   value = g_file_info_create_value (info, attr);
1899   if (value)
1900     _g_file_attribute_value_set_string (value, display_name);
1901 }
1902
1903 /**
1904  * g_file_info_set_edit_name:
1905  * @info: a #GFileInfo.
1906  * @edit_name: a string containing an edit name.
1907  * 
1908  * Sets the edit name for the current file.
1909  * See %G_FILE_ATTRIBUTE_STANDARD_EDIT_NAME.
1910  **/
1911 void
1912 g_file_info_set_edit_name (GFileInfo  *info,
1913                            const char *edit_name)
1914 {
1915   static guint32 attr = 0;
1916   GFileAttributeValue *value;
1917   
1918   g_return_if_fail (G_IS_FILE_INFO (info));
1919   g_return_if_fail (edit_name != NULL);
1920   
1921   if (attr == 0)
1922     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_EDIT_NAME);
1923   
1924   value = g_file_info_create_value (info, attr);
1925   if (value)
1926     _g_file_attribute_value_set_string (value, edit_name);
1927 }
1928
1929 /**
1930  * g_file_info_set_icon:
1931  * @info: a #GFileInfo.
1932  * @icon: a #GIcon.
1933  * 
1934  * Sets the icon for a given #GFileInfo. 
1935  * See %G_FILE_ATTRIBUTE_STANDARD_ICON.
1936  **/
1937 void
1938 g_file_info_set_icon (GFileInfo *info,
1939                       GIcon     *icon)
1940 {
1941   static guint32 attr = 0;
1942   GFileAttributeValue *value;
1943   
1944   g_return_if_fail (G_IS_FILE_INFO (info));
1945   g_return_if_fail (G_IS_ICON (icon));
1946   
1947   if (attr == 0)
1948     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_ICON);
1949   
1950   value = g_file_info_create_value (info, attr);
1951   if (value)
1952     _g_file_attribute_value_set_object (value, G_OBJECT (icon));
1953 }
1954
1955 /**
1956  * g_file_info_set_content_type:
1957  * @info: a #GFileInfo.
1958  * @content_type: a content type. See #GContentType.
1959  * 
1960  * Sets the content type attribute for a given #GFileInfo.
1961  * See %G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE.
1962  **/
1963 void
1964 g_file_info_set_content_type (GFileInfo  *info,
1965                               const char *content_type)
1966 {
1967   static guint32 attr = 0;
1968   GFileAttributeValue *value;
1969   
1970   g_return_if_fail (G_IS_FILE_INFO (info));
1971   g_return_if_fail (content_type != NULL);
1972   
1973   if (attr == 0)
1974     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE);
1975   
1976   value = g_file_info_create_value (info, attr);
1977   if (value)
1978     _g_file_attribute_value_set_string (value, content_type);
1979 }
1980
1981 /**
1982  * g_file_info_set_size:
1983  * @info: a #GFileInfo.
1984  * @size: a #goffset containing the file's size.
1985  * 
1986  * Sets the %G_FILE_ATTRIBUTE_STANDARD_SIZE attribute in the file info 
1987  * to the given size.
1988  **/
1989 void
1990 g_file_info_set_size (GFileInfo *info,
1991                       goffset    size)
1992 {
1993   static guint32 attr = 0;
1994   GFileAttributeValue *value;
1995   
1996   g_return_if_fail (G_IS_FILE_INFO (info));
1997   
1998   if (attr == 0)
1999     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_SIZE);
2000   
2001   value = g_file_info_create_value (info, attr);
2002   if (value)
2003     _g_file_attribute_value_set_uint64 (value, size);
2004 }
2005
2006 /**
2007  * g_file_info_set_modification_time
2008  * @info: a #GFileInfo.
2009  * @mtime: a #GTimeVal.
2010  * 
2011  * Sets the %G_FILE_ATTRIBUTE_TIME_MODIFIED attribute in the file
2012  * info to the given time value.
2013  **/
2014 void
2015 g_file_info_set_modification_time (GFileInfo *info,
2016                                    GTimeVal  *mtime)
2017 {
2018   static guint32 attr_mtime = 0, attr_mtime_usec;
2019   GFileAttributeValue *value;
2020   
2021   g_return_if_fail (G_IS_FILE_INFO (info));
2022   g_return_if_fail (mtime != NULL);
2023   
2024   if (attr_mtime == 0)
2025     {
2026       attr_mtime = lookup_attribute (G_FILE_ATTRIBUTE_TIME_MODIFIED);
2027       attr_mtime_usec = lookup_attribute (G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC);
2028     }
2029   
2030   value = g_file_info_create_value (info, attr_mtime);
2031   if (value)
2032     _g_file_attribute_value_set_uint64 (value, mtime->tv_sec);
2033   value = g_file_info_create_value (info, attr_mtime_usec);
2034   if (value)
2035     _g_file_attribute_value_set_uint32 (value, mtime->tv_usec);
2036 }
2037
2038 /**
2039  * g_file_info_set_symlink_target:
2040  * @info: a #GFileInfo.
2041  * @symlink_target: a static string containing a path to a symlink target.
2042  * 
2043  * Sets the %G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET attribute in the file info 
2044  * to the given symlink target.
2045  **/
2046 void
2047 g_file_info_set_symlink_target (GFileInfo  *info,
2048                                 const char *symlink_target)
2049 {
2050   static guint32 attr = 0;
2051   GFileAttributeValue *value;
2052   
2053   g_return_if_fail (G_IS_FILE_INFO (info));
2054   g_return_if_fail (symlink_target != NULL);
2055   
2056   if (attr == 0)
2057     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET);
2058   
2059   value = g_file_info_create_value (info, attr);
2060   if (value)
2061     _g_file_attribute_value_set_byte_string (value, symlink_target);
2062 }
2063
2064 /**
2065  * g_file_info_set_sort_order:
2066  * @info: a #GFileInfo.
2067  * @sort_order: a sort order integer.
2068  * 
2069  * Sets the sort order attribute in the file info structure. See 
2070  * %G_FILE_ATTRIBUTE_STANDARD_SORT_ORDER.
2071  **/
2072 void
2073 g_file_info_set_sort_order (GFileInfo *info,
2074                             gint32     sort_order)
2075 {
2076   static guint32 attr = 0;
2077   GFileAttributeValue *value;
2078   
2079   g_return_if_fail (G_IS_FILE_INFO (info));
2080   
2081   if (attr == 0)
2082     attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_SORT_ORDER);
2083   
2084   value = g_file_info_create_value (info, attr);
2085   if (value)
2086     _g_file_attribute_value_set_int32 (value, sort_order);
2087 }
2088
2089
2090 #define ON_STACK_MATCHERS 5
2091
2092 typedef struct {
2093   guint32 id;
2094   guint32 mask;
2095 } SubMatcher;
2096
2097 struct _GFileAttributeMatcher {
2098   gboolean all;
2099   SubMatcher sub_matchers[ON_STACK_MATCHERS];
2100   GArray *more_sub_matchers;
2101
2102   /* Interator */
2103   guint32 iterator_ns;
2104   int iterator_pos;
2105   int ref;
2106 };
2107
2108 static void
2109 matcher_add (GFileAttributeMatcher *matcher,
2110              guint                  id,
2111              guint                  mask)
2112 {
2113   SubMatcher *sub_matchers;
2114   int i;
2115   SubMatcher s;
2116
2117   for (i = 0; i < ON_STACK_MATCHERS; i++)
2118     {
2119       /* First empty spot, not found, use this */
2120       if (matcher->sub_matchers[i].id == 0)
2121         {
2122           matcher->sub_matchers[i].id = id;
2123           matcher->sub_matchers[i].mask = mask;
2124           return;
2125         }
2126       
2127       /* Already added */
2128       if (matcher->sub_matchers[i].id == id &&
2129           matcher->sub_matchers[i].mask == mask)
2130         return;
2131     }
2132
2133   if (matcher->more_sub_matchers == NULL)
2134     matcher->more_sub_matchers = g_array_new (FALSE, FALSE, sizeof (SubMatcher));
2135       
2136   sub_matchers = (SubMatcher *)matcher->more_sub_matchers->data;
2137   for (i = 0; i < matcher->more_sub_matchers->len; i++)
2138     {
2139       /* Already added */
2140       if (sub_matchers[i].id == id &&
2141           sub_matchers[i].mask == mask)
2142         return;
2143     }
2144
2145   s.id = id;
2146   s.mask = mask;
2147   
2148   g_array_append_val (matcher->more_sub_matchers, s);
2149 }
2150
2151 /**
2152  * g_file_attribute_matcher_new:
2153  * @attributes: an attribute string to match.
2154  * 
2155  * Creates a new file attribute matcher, which matches attributes 
2156  * against a given string. #GFileAttributeMatcher<!-- -->s are reference 
2157  * counted structures, and are created with a reference count of 1. If 
2158  * the number of references falls to 0, the #GFileAttributeMatcher is 
2159  * automatically destroyed.
2160  * 
2161  * The @attribute string should be formatted with specific keys separated
2162  * from namespaces with a double colon. Several "namespace::key" strings may be 
2163  * concatenated with a single comma (e.g. "standard::type,standard::is-hidden"). 
2164  * The wildcard "*" may be used to match all keys and namespaces, or 
2165  * "namespace::*" will match all keys in a given namespace. 
2166  * 
2167  * Examples of strings to use:
2168  * <table>
2169  * <title>File Attribute Matcher strings and results</title>
2170  * <tgroup cols='2' align='left'><thead>
2171  * <row><entry> Matcher String </entry><entry> Matches </entry></row></thead>
2172  * <tbody>
2173  * <row><entry>"*"</entry><entry>matches all attributes.</entry></row>
2174  * <row><entry>"standard::is-hidden"</entry><entry>matches only the key is-hidden in the standard namespace.</entry></row>
2175  * <row><entry>"standard::type,unix::*"</entry><entry>matches the type key in the standard namespace and
2176  * all keys in the unix namespace.</entry></row>
2177  * </tbody></tgroup>
2178  * </table>
2179  * 
2180  * Returns: a #GFileAttributeMatcher.
2181  **/
2182 GFileAttributeMatcher *
2183 g_file_attribute_matcher_new (const char *attributes)
2184 {
2185   char **split;
2186   char *colon;
2187   int i;
2188   GFileAttributeMatcher *matcher;
2189
2190   if (attributes == NULL || *attributes == '\0')
2191     return NULL;
2192
2193   matcher = g_malloc0 (sizeof (GFileAttributeMatcher));
2194   matcher->ref = 1;
2195
2196   split = g_strsplit (attributes, ",", -1);
2197
2198   for (i = 0; split[i] != NULL; i++)
2199     {
2200       if (strcmp (split[i], "*") == 0)
2201         matcher->all = TRUE;
2202       else
2203         {
2204           guint32 id, mask;
2205   
2206           colon = strstr (split[i], "::");
2207           if (colon != NULL &&
2208               !(colon[2] == 0 ||
2209                 (colon[2] == '*' &&
2210                  colon[3] == 0)))
2211             {
2212               id = lookup_attribute (split[i]);
2213               mask = 0xffffffff;
2214             }
2215           else
2216             {
2217               if (colon)
2218                 *colon = 0;
2219
2220               id = lookup_namespace (split[i]) << NS_POS;
2221               mask = NS_MASK << NS_POS;
2222             }
2223           
2224           matcher_add (matcher, id, mask);
2225         }
2226     }
2227
2228   g_strfreev (split);
2229
2230   return matcher;
2231 }
2232
2233 /**
2234  * g_file_attribute_matcher_ref:
2235  * @matcher: a #GFileAttributeMatcher.
2236  * 
2237  * References a file attribute matcher.
2238  * 
2239  * Returns: a #GFileAttributeMatcher.
2240  **/
2241 GFileAttributeMatcher *
2242 g_file_attribute_matcher_ref (GFileAttributeMatcher *matcher)
2243 {
2244   if (matcher)
2245     {
2246       g_return_val_if_fail (matcher->ref > 0, NULL);
2247       g_atomic_int_inc (&matcher->ref);
2248     }
2249   return matcher;
2250 }
2251
2252 /**
2253  * g_file_attribute_matcher_unref:
2254  * @matcher: a #GFileAttributeMatcher.
2255  * 
2256  * Unreferences @matcher. If the reference count falls below 1, 
2257  * the @matcher is automatically freed.
2258  * 
2259  **/
2260 void
2261 g_file_attribute_matcher_unref (GFileAttributeMatcher *matcher)
2262 {
2263   if (matcher)
2264     {
2265       g_return_if_fail (matcher->ref > 0);
2266       
2267       if (g_atomic_int_dec_and_test (&matcher->ref))
2268         {
2269           if (matcher->more_sub_matchers)
2270             g_array_free (matcher->more_sub_matchers, TRUE);
2271           
2272           g_free (matcher);
2273         }
2274     }
2275 }
2276
2277 /**
2278  * g_file_attribute_matcher_matches_only:
2279  * @matcher: a #GFileAttributeMatcher.
2280  * @attribute: a file attribute key.
2281  * 
2282  * Checks if a attribute matcher only matches a given attribute. Always
2283  * returns %FALSE if "*" was used when creating the matcher.
2284  * 
2285  * Returns: %TRUE if the matcher only matches @attribute. %FALSE otherwise.
2286  **/
2287 gboolean
2288 g_file_attribute_matcher_matches_only (GFileAttributeMatcher *matcher,
2289                                        const char            *attribute)
2290 {
2291   guint32 id;
2292
2293   g_return_val_if_fail (attribute != NULL && *attribute != '\0', FALSE);
2294
2295   if (matcher == NULL ||
2296       matcher->all)
2297     return FALSE;
2298   
2299   id = lookup_attribute (attribute);
2300
2301   if (matcher->sub_matchers[0].id != 0 &&
2302       matcher->sub_matchers[1].id == 0 &&
2303       matcher->sub_matchers[0].mask == 0xffffffff &&
2304       matcher->sub_matchers[0].id == id)
2305     return TRUE;
2306   
2307   return FALSE;
2308 }
2309
2310 static gboolean
2311 matcher_matches_id (GFileAttributeMatcher *matcher,
2312                     guint32                id)
2313 {
2314   SubMatcher *sub_matchers;
2315   int i;
2316   
2317   for (i = 0; i < ON_STACK_MATCHERS; i++)
2318     {
2319       if (matcher->sub_matchers[i].id == 0)
2320         return FALSE;
2321       
2322       if (matcher->sub_matchers[i].id == (id & matcher->sub_matchers[i].mask))
2323         return TRUE;
2324     }
2325
2326   if (matcher->more_sub_matchers)
2327     {
2328       sub_matchers = (SubMatcher *)matcher->more_sub_matchers->data;
2329       for (i = 0; i < matcher->more_sub_matchers->len; i++)
2330         {
2331           if (sub_matchers[i].id == (id & sub_matchers[i].mask))
2332             return TRUE;
2333         }
2334     }
2335   
2336   return FALSE;
2337 }
2338
2339 gboolean
2340 _g_file_attribute_matcher_matches_id (GFileAttributeMatcher *matcher,
2341                                       guint32                id)
2342 {
2343   /* We return a NULL matcher for an empty match string, so handle this */
2344   if (matcher == NULL)
2345     return FALSE;
2346   
2347   if (matcher->all)
2348     return TRUE;
2349   
2350   return matcher_matches_id (matcher, id);
2351 }
2352
2353 /**
2354  * g_file_attribute_matcher_matches:
2355  * @matcher: a #GFileAttributeMatcher.
2356  * @attribute: a file attribute key.
2357  *
2358  * Checks if an attribute will be matched by an attribute matcher. If 
2359  * the matcher was created with the "*" matching string, this function
2360  * will always return %TRUE.
2361  * 
2362  * Returns: %TRUE if @attribute matches @matcher. %FALSE otherwise.
2363  **/
2364 gboolean
2365 g_file_attribute_matcher_matches (GFileAttributeMatcher *matcher,
2366                                   const char            *attribute)
2367 {
2368   g_return_val_if_fail (attribute != NULL && *attribute != '\0', FALSE);
2369
2370   /* We return a NULL matcher for an empty match string, so handle this */
2371   if (matcher == NULL)
2372     return FALSE;
2373   
2374   if (matcher->all)
2375     return TRUE;
2376   
2377   return matcher_matches_id (matcher, lookup_attribute (attribute));
2378 }
2379
2380 /* return TRUE -> all */
2381 /**
2382  * g_file_attribute_matcher_enumerate_namespace:
2383  * @matcher: a #GFileAttributeMatcher.
2384  * @ns: a string containing a file attribute namespace.
2385  * 
2386  * Checks if the matcher will match all of the keys in a given namespace.
2387  * This will always return %TRUE if a wildcard character is in use (e.g. if 
2388  * matcher was created with "standard::*" and @ns is "standard", or if matcher was created
2389  * using "*" and namespace is anything.) 
2390  * 
2391  * TODO: this is awkwardly worded.
2392  * 
2393  * Returns: %TRUE if the matcher matches all of the entries
2394  * in the given @ns, %FALSE otherwise.
2395  **/
2396 gboolean
2397 g_file_attribute_matcher_enumerate_namespace (GFileAttributeMatcher *matcher,
2398                                               const char            *ns)
2399 {
2400   SubMatcher *sub_matchers;
2401   int ns_id;
2402   int i;
2403   
2404   g_return_val_if_fail (ns != NULL && *ns != '\0', FALSE);
2405
2406   /* We return a NULL matcher for an empty match string, so handle this */
2407   if (matcher == NULL)
2408     return FALSE;
2409   
2410   if (matcher->all)
2411     return TRUE;
2412
2413   ns_id = lookup_namespace (ns) << NS_POS;
2414
2415   for (i = 0; i < ON_STACK_MATCHERS; i++)
2416     {
2417       if (matcher->sub_matchers[i].id == ns_id)
2418         return TRUE;
2419     }
2420
2421   if (matcher->more_sub_matchers)
2422     {
2423       sub_matchers = (SubMatcher *)matcher->more_sub_matchers->data;
2424       for (i = 0; i < matcher->more_sub_matchers->len; i++)
2425         {
2426           if (sub_matchers[i].id == ns_id)
2427             return TRUE;
2428         }
2429     }
2430
2431   matcher->iterator_ns = ns_id;
2432   matcher->iterator_pos = 0;
2433   
2434   return FALSE;
2435 }
2436
2437 /**
2438  * g_file_attribute_matcher_enumerate_next:
2439  * @matcher: a #GFileAttributeMatcher.
2440  * 
2441  * Gets the next matched attribute from a #GFileAttributeMatcher.
2442  * 
2443  * Returns: a string containing the next attribute or %NULL if 
2444  * no more attribute exist.
2445  **/
2446 const char *
2447 g_file_attribute_matcher_enumerate_next (GFileAttributeMatcher *matcher)
2448 {
2449   int i;
2450   SubMatcher *sub_matcher;
2451
2452   /* We return a NULL matcher for an empty match string, so handle this */
2453   if (matcher == NULL)
2454     return NULL;
2455
2456   while (1)
2457     {
2458       i = matcher->iterator_pos++;
2459
2460       if (i < ON_STACK_MATCHERS)
2461         {
2462           if (matcher->sub_matchers[i].id == 0)
2463             return NULL;
2464
2465           sub_matcher = &matcher->sub_matchers[i];
2466         }
2467       else
2468         {
2469           if (matcher->more_sub_matchers == NULL)
2470             return NULL;
2471       
2472           i -= ON_STACK_MATCHERS;
2473           if (i < matcher->more_sub_matchers->len)
2474             sub_matcher = &g_array_index (matcher->more_sub_matchers, SubMatcher, i);
2475           else
2476             return NULL;
2477         }
2478
2479       if (sub_matcher->mask == 0xffffffff &&
2480           (sub_matcher->id & (NS_MASK << NS_POS)) == matcher->iterator_ns)
2481         return get_attribute_for_id (sub_matcher->id);
2482     }
2483 }
2484
2485 #define __G_FILE_INFO_C__
2486 #include "gioaliasdef.c"