kdbus: Fixup signal subscription
[platform/upstream/glib.git] / gio / gfileattribute.c
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 #include "config.h"
24
25 #include <string.h>
26
27 #include "gfileattribute.h"
28 #include "gfileattribute-priv.h"
29 #include <glib-object.h>
30 #include "glibintl.h"
31
32
33 /**
34  * _g_file_attribute_value_free:
35  * @attr: a #GFileAttributeValue.
36  *
37  * Frees the memory used by @attr.
38  *
39  **/
40 void
41 _g_file_attribute_value_free (GFileAttributeValue *attr)
42 {
43   g_return_if_fail (attr != NULL);
44
45   _g_file_attribute_value_clear (attr);
46   g_free (attr);
47 }
48
49 /**
50  * _g_file_attribute_value_clear:
51  * @attr: a #GFileAttributeValue.
52  *
53  * Clears the value of @attr and sets its type to
54  * %G_FILE_ATTRIBUTE_TYPE_INVALID.
55  *
56  **/
57 void
58 _g_file_attribute_value_clear (GFileAttributeValue *attr)
59 {
60   g_return_if_fail (attr != NULL);
61
62   if (attr->type == G_FILE_ATTRIBUTE_TYPE_STRING ||
63       attr->type == G_FILE_ATTRIBUTE_TYPE_BYTE_STRING)
64     g_free (attr->u.string);
65
66   if (attr->type == G_FILE_ATTRIBUTE_TYPE_STRINGV)
67     g_strfreev (attr->u.stringv);
68
69   if (attr->type == G_FILE_ATTRIBUTE_TYPE_OBJECT &&
70       attr->u.obj != NULL)
71     g_object_unref (attr->u.obj);
72
73   attr->type = G_FILE_ATTRIBUTE_TYPE_INVALID;
74 }
75
76 /**
77  * g_file_attribute_value_set:
78  * @attr: a #GFileAttributeValue to set the value in.
79  * @new_value: a #GFileAttributeValue to get the value from.
80  *
81  * Sets an attribute's value from another attribute.
82  **/
83 void
84 _g_file_attribute_value_set (GFileAttributeValue        *attr,
85                              const GFileAttributeValue *new_value)
86 {
87   g_return_if_fail (attr != NULL);
88   g_return_if_fail (new_value != NULL);
89
90   _g_file_attribute_value_clear (attr);
91   *attr = *new_value;
92
93   if (attr->type == G_FILE_ATTRIBUTE_TYPE_STRING ||
94       attr->type == G_FILE_ATTRIBUTE_TYPE_BYTE_STRING)
95     attr->u.string = g_strdup (attr->u.string);
96
97   if (attr->type == G_FILE_ATTRIBUTE_TYPE_STRINGV)
98     attr->u.stringv = g_strdupv (attr->u.stringv);
99
100   if (attr->type == G_FILE_ATTRIBUTE_TYPE_OBJECT &&
101       attr->u.obj != NULL)
102     g_object_ref (attr->u.obj);
103 }
104
105 /**
106  * _g_file_attribute_value_new:
107  *
108  * Creates a new file attribute.
109  *
110  * Returns: a #GFileAttributeValue.
111  **/
112 GFileAttributeValue *
113 _g_file_attribute_value_new (void)
114 {
115   GFileAttributeValue *attr;
116
117   attr = g_new (GFileAttributeValue, 1);
118   attr->type = G_FILE_ATTRIBUTE_TYPE_INVALID;
119   return attr;
120 }
121
122 gpointer
123 _g_file_attribute_value_peek_as_pointer (GFileAttributeValue *attr)
124 {
125   switch (attr->type) {
126   case G_FILE_ATTRIBUTE_TYPE_STRING:
127   case G_FILE_ATTRIBUTE_TYPE_BYTE_STRING:
128     return attr->u.string;
129   case G_FILE_ATTRIBUTE_TYPE_STRINGV:
130     return attr->u.stringv;
131   case G_FILE_ATTRIBUTE_TYPE_OBJECT:
132     return attr->u.obj;
133   default:
134     return (gpointer) &attr->u;
135   }
136 }
137
138 /**
139  * g_file_attribute_value_dup:
140  * @other: a #GFileAttributeValue to duplicate.
141  *
142  * Duplicates a file attribute.
143  *
144  * Returns: a duplicate of the @other.
145  **/
146 GFileAttributeValue *
147 _g_file_attribute_value_dup (const GFileAttributeValue *other)
148 {
149   GFileAttributeValue *attr;
150
151   g_return_val_if_fail (other != NULL, NULL);
152
153   attr = g_new (GFileAttributeValue, 1);
154   attr->type = G_FILE_ATTRIBUTE_TYPE_INVALID;
155   _g_file_attribute_value_set (attr, other);
156   return attr;
157 }
158
159 G_DEFINE_BOXED_TYPE (GFileAttributeInfoList, g_file_attribute_info_list,
160                      g_file_attribute_info_list_dup,
161                      g_file_attribute_info_list_unref)
162
163 static gboolean
164 valid_char (char c)
165 {
166   return c >= 32 && c <= 126 && c != '\\';
167 }
168
169 static char *
170 escape_byte_string (const char *str)
171 {
172   size_t i, len;
173   int num_invalid;
174   char *escaped_val, *p;
175   unsigned char c;
176   const char hex_digits[] = "0123456789abcdef";
177
178   len = strlen (str);
179
180   num_invalid = 0;
181   for (i = 0; i < len; i++)
182     {
183       if (!valid_char (str[i]))
184         num_invalid++;
185     }
186
187   if (num_invalid == 0)
188     return g_strdup (str);
189   else
190     {
191       escaped_val = g_malloc (len + num_invalid*3 + 1);
192
193       p = escaped_val;
194       for (i = 0; i < len; i++)
195         {
196           c = str[i];
197           if (valid_char (c))
198             *p++ = c;
199           else
200             {
201               *p++ = '\\';
202               *p++ = 'x';
203               *p++ = hex_digits[(c >> 4) & 0xf];
204               *p++ = hex_digits[c & 0xf];
205             }
206         }
207       *p++ = 0;
208       return escaped_val;
209     }
210 }
211
212 /**
213  * _g_file_attribute_value_as_string:
214  * @attr: a #GFileAttributeValue.
215  *
216  * Converts a #GFileAttributeValue to a string for display.
217  * The returned string should be freed when no longer needed.
218  *
219  * Returns: a string from the @attr, %NULL on error, or "<invalid>"
220  * if @attr is of type %G_FILE_ATTRIBUTE_TYPE_INVALID.
221  */
222 char *
223 _g_file_attribute_value_as_string (const GFileAttributeValue *attr)
224 {
225   GString *s;
226   int i;
227   char *str;
228
229   g_return_val_if_fail (attr != NULL, NULL);
230
231   switch (attr->type)
232     {
233     case G_FILE_ATTRIBUTE_TYPE_STRING:
234       str = g_strdup (attr->u.string);
235       break;
236     case G_FILE_ATTRIBUTE_TYPE_STRINGV:
237       s = g_string_new ("[");
238       for (i = 0; attr->u.stringv[i] != NULL; i++)
239         {
240           g_string_append (s, attr->u.stringv[i]);
241           if (attr->u.stringv[i+1] != NULL)
242             g_string_append (s, ", ");
243         }
244       g_string_append (s, "]");
245       str = g_string_free (s, FALSE);
246       break;
247     case G_FILE_ATTRIBUTE_TYPE_BYTE_STRING:
248       str = escape_byte_string (attr->u.string);
249       break;
250     case G_FILE_ATTRIBUTE_TYPE_BOOLEAN:
251       str = g_strdup_printf ("%s", attr->u.boolean?"TRUE":"FALSE");
252       break;
253     case G_FILE_ATTRIBUTE_TYPE_UINT32:
254       str = g_strdup_printf ("%u", (unsigned int)attr->u.uint32);
255       break;
256     case G_FILE_ATTRIBUTE_TYPE_INT32:
257       str = g_strdup_printf ("%i", (int)attr->u.int32);
258       break;
259     case G_FILE_ATTRIBUTE_TYPE_UINT64:
260       str = g_strdup_printf ("%"G_GUINT64_FORMAT, attr->u.uint64);
261       break;
262     case G_FILE_ATTRIBUTE_TYPE_INT64:
263       str = g_strdup_printf ("%"G_GINT64_FORMAT, attr->u.int64);
264       break;
265     case G_FILE_ATTRIBUTE_TYPE_OBJECT:
266       str = g_strdup_printf ("%s:%p", g_type_name_from_instance
267                                           ((GTypeInstance *) attr->u.obj),
268                                       attr->u.obj);
269       break;
270     case G_FILE_ATTRIBUTE_TYPE_INVALID:
271       str = g_strdup ("<unset>");
272       break;
273     default:
274       g_warning ("Invalid type in GFileInfo attribute");
275       str = g_strdup ("<invalid>");
276       break;
277     }
278
279   return str;
280 }
281
282 /**
283  * _g_file_attribute_value_get_string:
284  * @attr: a #GFileAttributeValue.
285  *
286  * Gets the string from a file attribute value. If the value is not the
287  * right type then %NULL will be returned.
288  *
289  * Returns: the UTF-8 string value contained within the attribute, or %NULL.
290  */
291 const char *
292 _g_file_attribute_value_get_string (const GFileAttributeValue *attr)
293 {
294   if (attr == NULL)
295     return NULL;
296
297   g_return_val_if_fail (attr->type == G_FILE_ATTRIBUTE_TYPE_STRING, NULL);
298
299   return attr->u.string;
300 }
301
302 /**
303  * _g_file_attribute_value_get_byte_string:
304  * @attr: a #GFileAttributeValue.
305  *
306  * Gets the byte string from a file attribute value. If the value is not the
307  * right type then %NULL will be returned.
308  *
309  * Returns: the byte string contained within the attribute or %NULL.
310  */
311 const char *
312 _g_file_attribute_value_get_byte_string (const GFileAttributeValue *attr)
313 {
314   if (attr == NULL)
315     return NULL;
316
317   g_return_val_if_fail (attr->type == G_FILE_ATTRIBUTE_TYPE_BYTE_STRING, NULL);
318
319   return attr->u.string;
320 }
321
322 char **
323 _g_file_attribute_value_get_stringv (const GFileAttributeValue *attr)
324 {
325   if (attr == NULL)
326     return NULL;
327
328   g_return_val_if_fail (attr->type == G_FILE_ATTRIBUTE_TYPE_STRINGV, NULL);
329
330   return attr->u.stringv;
331 }
332
333 /**
334  * _g_file_attribute_value_get_boolean:
335  * @attr: a #GFileAttributeValue.
336  *
337  * Gets the boolean value from a file attribute value. If the value is not the
338  * right type then %FALSE will be returned.
339  *
340  * Returns: the boolean value contained within the attribute, or %FALSE.
341  */
342 gboolean
343 _g_file_attribute_value_get_boolean (const GFileAttributeValue *attr)
344 {
345   if (attr == NULL)
346     return FALSE;
347
348   g_return_val_if_fail (attr->type == G_FILE_ATTRIBUTE_TYPE_BOOLEAN, FALSE);
349
350   return attr->u.boolean;
351 }
352
353 /**
354  * _g_file_attribute_value_get_uint32:
355  * @attr: a #GFileAttributeValue.
356  *
357  * Gets the unsigned 32-bit integer from a file attribute value. If the value
358  * is not the right type then 0 will be returned.
359  *
360  * Returns: the unsigned 32-bit integer from the attribute, or 0.
361  */
362 guint32
363 _g_file_attribute_value_get_uint32 (const GFileAttributeValue *attr)
364 {
365   if (attr == NULL)
366     return 0;
367
368   g_return_val_if_fail (attr->type == G_FILE_ATTRIBUTE_TYPE_UINT32, 0);
369
370   return attr->u.uint32;
371 }
372
373 /**
374  * _g_file_attribute_value_get_int32:
375  * @attr: a #GFileAttributeValue.
376  *
377  * Gets the signed 32-bit integer from a file attribute value. If the value
378  * is not the right type then 0 will be returned.
379  *
380  * Returns: the signed 32-bit integer from the attribute, or 0.
381  */
382 gint32
383 _g_file_attribute_value_get_int32 (const GFileAttributeValue *attr)
384 {
385   if (attr == NULL)
386     return 0;
387
388   g_return_val_if_fail (attr->type == G_FILE_ATTRIBUTE_TYPE_INT32, 0);
389
390   return attr->u.int32;
391 }
392
393 /**
394  * _g_file_attribute_value_get_uint64:
395  * @attr: a #GFileAttributeValue.
396  *
397  * Gets the unsigned 64-bit integer from a file attribute value. If the value
398  * is not the right type then 0 will be returned.
399  *
400  * Returns: the unsigned 64-bit integer from the attribute, or 0.
401  */
402 guint64
403 _g_file_attribute_value_get_uint64 (const GFileAttributeValue *attr)
404 {
405   if (attr == NULL)
406     return 0;
407
408   g_return_val_if_fail (attr->type == G_FILE_ATTRIBUTE_TYPE_UINT64, 0);
409
410   return attr->u.uint64;
411 }
412
413 /**
414  * _g_file_attribute_value_get_int64:
415  * @attr: a #GFileAttributeValue.
416  *
417  * Gets the signed 64-bit integer from a file attribute value. If the value
418  * is not the right type then 0 will be returned.
419  *
420  * Returns: the signed 64-bit integer from the attribute, or 0.
421  */
422 gint64
423 _g_file_attribute_value_get_int64 (const GFileAttributeValue *attr)
424 {
425   if (attr == NULL)
426     return 0;
427
428   g_return_val_if_fail (attr->type == G_FILE_ATTRIBUTE_TYPE_INT64, 0);
429
430   return attr->u.int64;
431 }
432
433 /**
434  * _g_file_attribute_value_get_object:
435  * @attr: a #GFileAttributeValue.
436  *
437  * Gets the GObject from a file attribute value. If the value
438  * is not the right type then %NULL will be returned.
439  *
440  * Returns: the GObject from the attribute, or %NULL.
441  **/
442 GObject *
443 _g_file_attribute_value_get_object (const GFileAttributeValue *attr)
444 {
445   if (attr == NULL)
446     return NULL;
447
448   g_return_val_if_fail (attr->type == G_FILE_ATTRIBUTE_TYPE_OBJECT, NULL);
449
450   return attr->u.obj;
451 }
452
453
454 void
455 _g_file_attribute_value_set_from_pointer (GFileAttributeValue *value,
456                                           GFileAttributeType   type,
457                                           gpointer             value_p,
458                                           gboolean             dup)
459 {
460   _g_file_attribute_value_clear (value);
461   value->type = type;
462   switch (type)
463     {
464     case G_FILE_ATTRIBUTE_TYPE_STRING:
465     case G_FILE_ATTRIBUTE_TYPE_BYTE_STRING:
466       if (dup)
467         value->u.string = g_strdup (value_p);
468       else
469         value->u.string = value_p;
470       break;
471
472     case G_FILE_ATTRIBUTE_TYPE_STRINGV:
473       if (dup)
474         value->u.stringv = g_strdupv (value_p);
475       else
476         value->u.stringv = value_p;
477       break;
478
479     case G_FILE_ATTRIBUTE_TYPE_OBJECT:
480       if (dup)
481         value->u.obj = g_object_ref (value_p);
482       else
483         value->u.obj = value_p;
484       break;
485
486     case G_FILE_ATTRIBUTE_TYPE_BOOLEAN:
487       value->u.boolean = *(gboolean *)value_p;
488       break;
489
490     case G_FILE_ATTRIBUTE_TYPE_UINT32:
491       value->u.uint32 = *(guint32 *)value_p;
492       break;
493
494     case G_FILE_ATTRIBUTE_TYPE_INT32:
495       value->u.int32 = *(gint32 *)value_p;
496       break;
497
498     case G_FILE_ATTRIBUTE_TYPE_UINT64:
499       value->u.uint64 = *(guint64 *)value_p;
500       break;
501
502     case G_FILE_ATTRIBUTE_TYPE_INT64:
503       value->u.int64 = *(gint64 *)value_p;
504       break;
505
506     case G_FILE_ATTRIBUTE_TYPE_INVALID:
507       break;
508
509     default:
510       g_warning ("Unknown type specified in g_file_info_set_attribute");
511       break;
512     }
513 }
514
515 /**
516  * _g_file_attribute_value_set_string:
517  * @attr: a #GFileAttributeValue.
518  * @string: a UTF-8 string to set within the type.
519  *
520  * Sets the attribute value to a given UTF-8 string.
521  */
522 void
523 _g_file_attribute_value_set_string (GFileAttributeValue *attr,
524                                     const char          *string)
525 {
526   g_return_if_fail (attr != NULL);
527   g_return_if_fail (string != NULL);
528
529   _g_file_attribute_value_clear (attr);
530   attr->type = G_FILE_ATTRIBUTE_TYPE_STRING;
531   attr->u.string = g_strdup (string);
532 }
533
534 /**
535  * _g_file_attribute_value_set_byte_string:
536  * @attr: a #GFileAttributeValue.
537  * @string: a byte string to set within the type.
538  *
539  * Sets the attribute value to a given byte string.
540  */
541 void
542 _g_file_attribute_value_set_byte_string (GFileAttributeValue *attr,
543                                          const char          *string)
544 {
545   g_return_if_fail (attr != NULL);
546   g_return_if_fail (string != NULL);
547
548   _g_file_attribute_value_clear (attr);
549   attr->type = G_FILE_ATTRIBUTE_TYPE_BYTE_STRING;
550   attr->u.string = g_strdup (string);
551 }
552
553 void
554 _g_file_attribute_value_set_stringv (GFileAttributeValue *attr,
555                                      char               **value)
556 {
557   g_return_if_fail (attr != NULL);
558   g_return_if_fail (value != NULL);
559
560   _g_file_attribute_value_clear (attr);
561   attr->type = G_FILE_ATTRIBUTE_TYPE_STRINGV;
562   attr->u.stringv = g_strdupv (value);
563 }
564
565
566 /**
567  * _g_file_attribute_value_set_boolean:
568  * @attr: a #GFileAttributeValue.
569  * @value: a #gboolean to set within the type.
570  *
571  * Sets the attribute value to the given boolean value.
572  */
573 void
574 _g_file_attribute_value_set_boolean (GFileAttributeValue *attr,
575                                      gboolean             value)
576 {
577   g_return_if_fail (attr != NULL);
578
579   _g_file_attribute_value_clear (attr);
580   attr->type = G_FILE_ATTRIBUTE_TYPE_BOOLEAN;
581   attr->u.boolean = !!value;
582 }
583
584 /**
585  * _g_file_attribute_value_set_uint32:
586  * @attr: a #GFileAttributeValue.
587  * @value: a #guint32 to set within the type.
588  *
589  * Sets the attribute value to the given unsigned 32-bit integer.
590  */
591 void
592 _g_file_attribute_value_set_uint32 (GFileAttributeValue *attr,
593                                     guint32              value)
594 {
595   g_return_if_fail (attr != NULL);
596
597   _g_file_attribute_value_clear (attr);
598   attr->type = G_FILE_ATTRIBUTE_TYPE_UINT32;
599   attr->u.uint32 = value;
600 }
601
602 /**
603  * _g_file_attribute_value_set_int32:
604  * @attr: a #GFileAttributeValue.
605  * @value: a #gint32 to set within the type.
606  *
607  * Sets the attribute value to the given signed 32-bit integer.
608  */
609 void
610 _g_file_attribute_value_set_int32 (GFileAttributeValue *attr,
611                                    gint32               value)
612 {
613   g_return_if_fail (attr != NULL);
614
615   _g_file_attribute_value_clear (attr);
616   attr->type = G_FILE_ATTRIBUTE_TYPE_INT32;
617   attr->u.int32 = value;
618 }
619
620 /**
621  * _g_file_attribute_value_set_uint64:
622  * @attr: a #GFileAttributeValue.
623  * @value: a #guint64 to set within the type.
624  *
625  * Sets the attribute value to a given unsigned 64-bit integer.
626  */
627 void
628 _g_file_attribute_value_set_uint64 (GFileAttributeValue *attr,
629                                     guint64              value)
630 {
631   g_return_if_fail (attr != NULL);
632
633   _g_file_attribute_value_clear (attr);
634   attr->type = G_FILE_ATTRIBUTE_TYPE_UINT64;
635   attr->u.uint64 = value;
636 }
637
638 /**
639  * _g_file_attribute_value_set_int64:
640  * @attr: a #GFileAttributeValue.
641  * @value: a #gint64 to set within the type.
642  *
643  * Sets the attribute value to a given signed 64-bit integer.
644  */
645 void
646 _g_file_attribute_value_set_int64 (GFileAttributeValue *attr,
647                                    gint64               value)
648 {
649   g_return_if_fail (attr != NULL);
650
651   _g_file_attribute_value_clear (attr);
652   attr->type = G_FILE_ATTRIBUTE_TYPE_INT64;
653   attr->u.int64 = value;
654 }
655
656 /**
657  * _g_file_attribute_value_set_object:
658  * @attr: a #GFileAttributeValue.
659  * @obj: a #GObject.
660  *
661  * Sets the attribute to contain the value @obj.
662  * The @attr references the GObject internally.
663  */
664 void
665 _g_file_attribute_value_set_object (GFileAttributeValue *attr,
666                                     GObject             *obj)
667 {
668   g_return_if_fail (attr != NULL);
669   g_return_if_fail (obj != NULL);
670
671   _g_file_attribute_value_clear (attr);
672   attr->type = G_FILE_ATTRIBUTE_TYPE_OBJECT;
673   attr->u.obj = g_object_ref (obj);
674 }
675
676 typedef struct {
677   GFileAttributeInfoList public;
678   GArray *array;
679   int ref_count;
680 } GFileAttributeInfoListPriv;
681
682 static void
683 list_update_public (GFileAttributeInfoListPriv *priv)
684 {
685   priv->public.infos = (GFileAttributeInfo *)priv->array->data;
686   priv->public.n_infos = priv->array->len;
687 }
688
689 /**
690  * g_file_attribute_info_list_new:
691  *
692  * Creates a new file attribute info list.
693  *
694  * Returns: a #GFileAttributeInfoList.
695  */
696 GFileAttributeInfoList *
697 g_file_attribute_info_list_new (void)
698 {
699   GFileAttributeInfoListPriv *priv;
700
701   priv = g_new0 (GFileAttributeInfoListPriv, 1);
702
703   priv->ref_count = 1;
704   priv->array = g_array_new (TRUE, FALSE, sizeof (GFileAttributeInfo));
705
706   list_update_public (priv);
707
708   return (GFileAttributeInfoList *)priv;
709 }
710
711 /**
712  * g_file_attribute_info_list_dup:
713  * @list: a #GFileAttributeInfoList to duplicate.
714  *
715  * Makes a duplicate of a file attribute info list.
716  *
717  * Returns: a copy of the given @list.
718  */
719 GFileAttributeInfoList *
720 g_file_attribute_info_list_dup (GFileAttributeInfoList *list)
721 {
722   GFileAttributeInfoListPriv *new;
723   int i;
724
725   g_return_val_if_fail (list != NULL, NULL);
726
727   new = g_new0 (GFileAttributeInfoListPriv, 1);
728   new->ref_count = 1;
729   new->array = g_array_new (TRUE, FALSE, sizeof (GFileAttributeInfo));
730
731   g_array_set_size (new->array, list->n_infos);
732   list_update_public (new);
733   for (i = 0; i < list->n_infos; i++)
734     {
735       new->public.infos[i].name = g_strdup (list->infos[i].name);
736       new->public.infos[i].type = list->infos[i].type;
737       new->public.infos[i].flags = list->infos[i].flags;
738     }
739
740   return (GFileAttributeInfoList *)new;
741 }
742
743 /**
744  * g_file_attribute_info_list_ref:
745  * @list: a #GFileAttributeInfoList to reference.
746  *
747  * References a file attribute info list.
748  *
749  * Returns: #GFileAttributeInfoList or %NULL on error.
750  */
751 GFileAttributeInfoList *
752 g_file_attribute_info_list_ref (GFileAttributeInfoList *list)
753 {
754   GFileAttributeInfoListPriv *priv = (GFileAttributeInfoListPriv *)list;
755   int old_ref_count;
756
757   g_return_val_if_fail (list != NULL, NULL);
758
759   old_ref_count = g_atomic_int_add (&priv->ref_count, 1);
760   g_return_val_if_fail (old_ref_count > 0, NULL);
761
762   return list;
763 }
764
765 /**
766  * g_file_attribute_info_list_unref:
767  * @list: The #GFileAttributeInfoList to unreference.
768  *
769  * Removes a reference from the given @list. If the reference count
770  * falls to zero, the @list is deleted.
771  */
772 void
773 g_file_attribute_info_list_unref (GFileAttributeInfoList *list)
774 {
775   GFileAttributeInfoListPriv *priv = (GFileAttributeInfoListPriv *)list;
776   int i;
777
778   g_return_if_fail (list != NULL);
779   g_return_if_fail (priv->ref_count > 0);
780
781   if (g_atomic_int_dec_and_test (&priv->ref_count))
782     {
783       for (i = 0; i < list->n_infos; i++)
784         g_free (list->infos[i].name);
785       g_array_free (priv->array, TRUE);
786       g_free (list);
787     }
788 }
789
790 static int
791 g_file_attribute_info_list_bsearch (GFileAttributeInfoList *list,
792                                     const char             *name)
793 {
794   int start, end, mid;
795
796   start = 0;
797   end = list->n_infos;
798
799   while (start != end)
800     {
801       mid = start + (end - start) / 2;
802
803       if (strcmp (name, list->infos[mid].name) < 0)
804         end = mid;
805       else if (strcmp (name, list->infos[mid].name) > 0)
806         start = mid + 1;
807       else
808         return mid;
809     }
810   return start;
811 }
812
813 /**
814  * g_file_attribute_info_list_lookup:
815  * @list: a #GFileAttributeInfoList.
816  * @name: the name of the attribute to look up.
817  *
818  * Gets the file attribute with the name @name from @list.
819  *
820  * Returns: a #GFileAttributeInfo for the @name, or %NULL if an
821  * attribute isn't found.
822  */
823 const GFileAttributeInfo *
824 g_file_attribute_info_list_lookup (GFileAttributeInfoList *list,
825                                    const char             *name)
826 {
827   int i;
828
829   g_return_val_if_fail (list != NULL, NULL);
830   g_return_val_if_fail (name != NULL, NULL);
831
832   i = g_file_attribute_info_list_bsearch (list, name);
833
834   if (i < list->n_infos && strcmp (list->infos[i].name, name) == 0)
835     return &list->infos[i];
836
837   return NULL;
838 }
839
840 /**
841  * g_file_attribute_info_list_add:
842  * @list: a #GFileAttributeInfoList.
843  * @name: the name of the attribute to add.
844  * @type: the #GFileAttributeType for the attribute.
845  * @flags: #GFileAttributeInfoFlags for the attribute.
846  *
847  * Adds a new attribute with @name to the @list, setting
848  * its @type and @flags.
849  */
850 void
851 g_file_attribute_info_list_add (GFileAttributeInfoList *list,
852                                 const char             *name,
853                                 GFileAttributeType      type,
854                                 GFileAttributeInfoFlags flags)
855 {
856   GFileAttributeInfoListPriv *priv = (GFileAttributeInfoListPriv *)list;
857   GFileAttributeInfo info;
858   int i;
859
860   g_return_if_fail (list != NULL);
861   g_return_if_fail (name != NULL);
862
863   i = g_file_attribute_info_list_bsearch (list, name);
864
865   if (i < list->n_infos && strcmp (list->infos[i].name, name) == 0)
866     {
867       list->infos[i].type = type;
868       return;
869     }
870
871   info.name = g_strdup (name);
872   info.type = type;
873   info.flags = flags;
874   g_array_insert_vals (priv->array, i, &info, 1);
875
876   list_update_public (priv);
877 }