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