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