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