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