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