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