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