Coverage Report

Created: 2025-07-01 07:09

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