Coverage Report

Created: 2026-10-17 07:33

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