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