gio/tests: fix race when generating code
[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  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General
16  * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
17  *
18  * Author: Alexander Larsson <alexl@redhat.com>
19  */
20
21 #include "config.h"
22
23 #include <string.h>
24
25 #include "gfileattribute.h"
26 #include "gfileattribute-priv.h"
27 #include <glib-object.h>
28 #include "glibintl.h"
29
30
31 /**
32  * SECTION:gfileattribute
33  * @short_description: Key-Value Paired File Attributes
34  * @include: gio/gio.h
35  * @see_also: #GFile, #GFileInfo
36  *
37  * File attributes in GIO consist of a list of key-value pairs.
38  *
39  * Keys are strings that contain a key namespace and a key name, separated
40  * by a colon, e.g. "namespace::keyname". Namespaces are included to sort
41  * key-value pairs by namespaces for relevance. Keys can be retrived
42  * using wildcards, e.g. "standard::*" will return all of the keys in the
43  * "standard" namespace.
44  *
45  * The list of possible attributes for a filesystem (pointed to by a #GFile) is
46  * available as a #GFileAttributeInfoList. This list is queryable by key names
47  * as indicated earlier.
48  *
49  * Information is stored within the list in #GFileAttributeInfo structures.
50  * The info structure can store different types, listed in the enum
51  * #GFileAttributeType. Upon creation of a #GFileAttributeInfo, the type will
52  * be set to %G_FILE_ATTRIBUTE_TYPE_INVALID.
53  *
54  * Classes that implement #GFileIface will create a #GFileAttributeInfoList and
55  * install default keys and values for their given file system, architecture,
56  * and other possible implementation details (e.g., on a UNIX system, a file
57  * attribute key will be registered for the user id for a given file).
58  *
59  * ## Default Namespaces
60  *
61  * - `"standard"`: The "Standard" namespace. General file information that
62  *   any application may need should be put in this namespace. Examples
63  *   include the file's name, type, and size.
64  * - `"etag`: The [Entity Tag][gfile-etag] namespace. Currently, the only key
65  *   in this namespace is "value", which contains the value of the current
66  *   entity tag.
67  * - `"id"`: The "Identification" namespace. This namespace is used by file
68  *   managers and applications that list directories to check for loops and
69  *   to uniquely identify files.
70  * - `"access"`: The "Access" namespace. Used to check if a user has the
71  *   proper privileges to access files and perform file operations. Keys in
72  *   this namespace are made to be generic and easily understood, e.g. the
73  *   "can_read" key is %TRUE if the current user has permission to read the
74  *   file. UNIX permissions and NTFS ACLs in Windows should be mapped to
75  *   these values.
76  * - `"mountable"`: The "Mountable" namespace. Includes simple boolean keys
77  *   for checking if a file or path supports mount operations, e.g. mount,
78  *   unmount, eject. These are used for files of type %G_FILE_TYPE_MOUNTABLE.
79  * - `"time"`: The "Time" namespace. Includes file access, changed, created
80  *   times.
81  * - `"unix"`: The "Unix" namespace. Includes UNIX-specific information and
82  *   may not be available for all files. Examples include the UNIX "UID",
83  *   "GID", etc.
84  * - `"dos"`: The "DOS" namespace. Includes DOS-specific information and may
85  *   not be available for all files. Examples include "is_system" for checking
86  *   if a file is marked as a system file, and "is_archive" for checking if a
87  *   file is marked as an archive file.
88  * - `"owner"`: The "Owner" namespace. Includes information about who owns a
89  *   file. May not be available for all file systems. Examples include "user"
90  *   for getting the user name of the file owner. This information is often
91  *   mapped from some backend specific data such as a UNIX UID.
92  * - `"thumbnail"`: The "Thumbnail" namespace. Includes information about file
93  *   thumbnails and their location within the file system. Examples of keys in
94  *   this namespace include "path" to get the location of a thumbnail, "failed"
95  *   to check if thumbnailing of the file failed, and "is-valid" to check if
96  *   the thumbnail is outdated.
97  * - `"filesystem"`: The "Filesystem" namespace. Gets information about the
98  *   file system where a file is located, such as its type, how much space is
99  *   left available, and the overall size of the file system.
100  * - `"gvfs"`: The "GVFS" namespace. Keys in this namespace contain information
101  *   about the current GVFS backend in use.
102  * - `"xattr"`: The "xattr" namespace. Gets information about extended
103  *   user attributes. See attr(5). The "user." prefix of the extended user
104  *   attribute name is stripped away when constructing keys in this namespace,
105  *   e.g. "xattr::mime_type" for the extended attribute with the name
106  *   "user.mime_type". Note that this information is only available if
107  *   GLib has been built with extended attribute support.
108  * - `"xattr-sys"`: The "xattr-sys" namespace. Gets information about
109  *   extended attributes which are not user-specific. See attr(5). Note
110  *   that this information is only available if GLib has been built with
111  *   extended attribute support.
112  * - `"selinux"`: The "SELinux" namespace. Includes information about the
113  *   SELinux context of files. Note that this information is only available
114  *   if GLib has been built with SELinux support.
115  *
116  * Please note that these are not all of the possible namespaces.
117  * More namespaces can be added from GIO modules or by individual applications.
118  * For more information about writing GIO modules, see #GIOModule.
119  *
120  * <!-- TODO: Implementation note about using extended attributes on supported
121  * file systems -->
122  *
123  * ## Default Keys
124  *
125  * For a list of the built-in keys and their types, see the
126  * [GFileInfo][GFileInfo] documentation.
127  *
128  * Note that there are no predefined keys in the "xattr" and "xattr-sys"
129  * namespaces. Keys for the "xattr" namespace are constructed by stripping
130  * away the "user." prefix from the extended user attribute, and prepending
131  * "xattr::". Keys for the "xattr-sys" namespace are constructed by
132  * concatenating "xattr-sys::" with the extended attribute name. All extended
133  * attribute values are returned as hex-encoded strings in which bytes outside
134  * the ASCII range are encoded as escape sequences of the form \x`nn`
135  * where `nn` is a 2-digit hexadecimal number.
136  */
137
138 /*
139  * _g_file_attribute_value_free:
140  * @attr: a #GFileAttributeValue.
141  *
142  * Frees the memory used by @attr.
143  *
144  **/
145 void
146 _g_file_attribute_value_free (GFileAttributeValue *attr)
147 {
148   g_return_if_fail (attr != NULL);
149
150   _g_file_attribute_value_clear (attr);
151   g_free (attr);
152 }
153
154 /*
155  * _g_file_attribute_value_clear:
156  * @attr: a #GFileAttributeValue.
157  *
158  * Clears the value of @attr and sets its type to
159  * %G_FILE_ATTRIBUTE_TYPE_INVALID.
160  *
161  **/
162 void
163 _g_file_attribute_value_clear (GFileAttributeValue *attr)
164 {
165   g_return_if_fail (attr != NULL);
166
167   if (attr->type == G_FILE_ATTRIBUTE_TYPE_STRING ||
168       attr->type == G_FILE_ATTRIBUTE_TYPE_BYTE_STRING)
169     g_free (attr->u.string);
170
171   if (attr->type == G_FILE_ATTRIBUTE_TYPE_STRINGV)
172     g_strfreev (attr->u.stringv);
173
174   if (attr->type == G_FILE_ATTRIBUTE_TYPE_OBJECT &&
175       attr->u.obj != NULL)
176     g_object_unref (attr->u.obj);
177
178   attr->type = G_FILE_ATTRIBUTE_TYPE_INVALID;
179 }
180
181 /*
182  * g_file_attribute_value_set:
183  * @attr: a #GFileAttributeValue to set the value in.
184  * @new_value: a #GFileAttributeValue to get the value from.
185  *
186  * Sets an attribute's value from another attribute.
187  **/
188 void
189 _g_file_attribute_value_set (GFileAttributeValue        *attr,
190                              const GFileAttributeValue *new_value)
191 {
192   g_return_if_fail (attr != NULL);
193   g_return_if_fail (new_value != NULL);
194
195   _g_file_attribute_value_clear (attr);
196   *attr = *new_value;
197
198   if (attr->type == G_FILE_ATTRIBUTE_TYPE_STRING ||
199       attr->type == G_FILE_ATTRIBUTE_TYPE_BYTE_STRING)
200     attr->u.string = g_strdup (attr->u.string);
201
202   if (attr->type == G_FILE_ATTRIBUTE_TYPE_STRINGV)
203     attr->u.stringv = g_strdupv (attr->u.stringv);
204
205   if (attr->type == G_FILE_ATTRIBUTE_TYPE_OBJECT &&
206       attr->u.obj != NULL)
207     g_object_ref (attr->u.obj);
208 }
209
210 /*
211  * _g_file_attribute_value_new:
212  *
213  * Creates a new file attribute.
214  *
215  * Returns: a #GFileAttributeValue.
216  **/
217 GFileAttributeValue *
218 _g_file_attribute_value_new (void)
219 {
220   GFileAttributeValue *attr;
221
222   attr = g_new (GFileAttributeValue, 1);
223   attr->type = G_FILE_ATTRIBUTE_TYPE_INVALID;
224   return attr;
225 }
226
227 gpointer
228 _g_file_attribute_value_peek_as_pointer (GFileAttributeValue *attr)
229 {
230   switch (attr->type) {
231   case G_FILE_ATTRIBUTE_TYPE_STRING:
232   case G_FILE_ATTRIBUTE_TYPE_BYTE_STRING:
233     return attr->u.string;
234   case G_FILE_ATTRIBUTE_TYPE_STRINGV:
235     return attr->u.stringv;
236   case G_FILE_ATTRIBUTE_TYPE_OBJECT:
237     return attr->u.obj;
238   default:
239     return (gpointer) &attr->u;
240   }
241 }
242
243 /*
244  * g_file_attribute_value_dup:
245  * @other: a #GFileAttributeValue to duplicate.
246  *
247  * Duplicates a file attribute.
248  *
249  * Returns: a duplicate of the @other.
250  **/
251 GFileAttributeValue *
252 _g_file_attribute_value_dup (const GFileAttributeValue *other)
253 {
254   GFileAttributeValue *attr;
255
256   g_return_val_if_fail (other != NULL, NULL);
257
258   attr = g_new (GFileAttributeValue, 1);
259   attr->type = G_FILE_ATTRIBUTE_TYPE_INVALID;
260   _g_file_attribute_value_set (attr, other);
261   return attr;
262 }
263
264 G_DEFINE_BOXED_TYPE (GFileAttributeInfoList, g_file_attribute_info_list,
265                      g_file_attribute_info_list_dup,
266                      g_file_attribute_info_list_unref)
267
268 static gboolean
269 valid_char (char c)
270 {
271   return c >= 32 && c <= 126 && c != '\\';
272 }
273
274 static char *
275 escape_byte_string (const char *str)
276 {
277   size_t len;
278   int num_invalid, i;
279   char *escaped_val, *p;
280   unsigned char c;
281   const char hex_digits[] = "0123456789abcdef";
282
283   len = strlen (str);
284
285   num_invalid = 0;
286   for (i = 0; i < len; i++)
287     {
288       if (!valid_char (str[i]))
289         num_invalid++;
290     }
291
292   if (num_invalid == 0)
293     return g_strdup (str);
294   else
295     {
296       escaped_val = g_malloc (len + num_invalid*3 + 1);
297
298       p = escaped_val;
299       for (i = 0; i < len; i++)
300         {
301           c = str[i];
302           if (valid_char (c))
303             *p++ = c;
304           else
305             {
306               *p++ = '\\';
307               *p++ = 'x';
308               *p++ = hex_digits[(c >> 4) & 0xf];
309               *p++ = hex_digits[c & 0xf];
310             }
311         }
312       *p++ = 0;
313       return escaped_val;
314     }
315 }
316
317 /*
318  * _g_file_attribute_value_as_string:
319  * @attr: a #GFileAttributeValue.
320  *
321  * Converts a #GFileAttributeValue to a string for display.
322  * The returned string should be freed when no longer needed.
323  *
324  * Returns: a string from the @attr, %NULL on error, or "<invalid>"
325  * if @attr is of type %G_FILE_ATTRIBUTE_TYPE_INVALID.
326  */
327 char *
328 _g_file_attribute_value_as_string (const GFileAttributeValue *attr)
329 {
330   GString *s;
331   int i;
332   char *str;
333
334   g_return_val_if_fail (attr != NULL, NULL);
335
336   switch (attr->type)
337     {
338     case G_FILE_ATTRIBUTE_TYPE_STRING:
339       str = g_strdup (attr->u.string);
340       break;
341     case G_FILE_ATTRIBUTE_TYPE_STRINGV:
342       s = g_string_new ("[");
343       for (i = 0; attr->u.stringv[i] != NULL; i++)
344         {
345           g_string_append (s, attr->u.stringv[i]);
346           if (attr->u.stringv[i+1] != NULL)
347             g_string_append (s, ", ");
348         }
349       g_string_append (s, "]");
350       str = g_string_free (s, FALSE);
351       break;
352     case G_FILE_ATTRIBUTE_TYPE_BYTE_STRING:
353       str = escape_byte_string (attr->u.string);
354       break;
355     case G_FILE_ATTRIBUTE_TYPE_BOOLEAN:
356       str = g_strdup_printf ("%s", attr->u.boolean?"TRUE":"FALSE");
357       break;
358     case G_FILE_ATTRIBUTE_TYPE_UINT32:
359       str = g_strdup_printf ("%u", (unsigned int)attr->u.uint32);
360       break;
361     case G_FILE_ATTRIBUTE_TYPE_INT32:
362       str = g_strdup_printf ("%i", (int)attr->u.int32);
363       break;
364     case G_FILE_ATTRIBUTE_TYPE_UINT64:
365       str = g_strdup_printf ("%"G_GUINT64_FORMAT, attr->u.uint64);
366       break;
367     case G_FILE_ATTRIBUTE_TYPE_INT64:
368       str = g_strdup_printf ("%"G_GINT64_FORMAT, attr->u.int64);
369       break;
370     case G_FILE_ATTRIBUTE_TYPE_OBJECT:
371       str = g_strdup_printf ("%s:%p", g_type_name_from_instance
372                                           ((GTypeInstance *) attr->u.obj),
373                                       attr->u.obj);
374       break;
375     case G_FILE_ATTRIBUTE_TYPE_INVALID:
376       str = g_strdup ("<unset>");
377       break;
378     default:
379       g_warning ("Invalid type in GFileInfo attribute");
380       str = g_strdup ("<invalid>");
381       break;
382     }
383
384   return str;
385 }
386
387 /*
388  * _g_file_attribute_value_get_string:
389  * @attr: a #GFileAttributeValue.
390  *
391  * Gets the string from a file attribute value. If the value is not the
392  * right type then %NULL will be returned.
393  *
394  * Returns: the UTF-8 string value contained within the attribute, or %NULL.
395  */
396 const char *
397 _g_file_attribute_value_get_string (const GFileAttributeValue *attr)
398 {
399   if (attr == NULL)
400     return NULL;
401
402   g_return_val_if_fail (attr->type == G_FILE_ATTRIBUTE_TYPE_STRING, NULL);
403
404   return attr->u.string;
405 }
406
407 /*
408  * _g_file_attribute_value_get_byte_string:
409  * @attr: a #GFileAttributeValue.
410  *
411  * Gets the byte string from a file attribute value. If the value is not the
412  * right type then %NULL will be returned.
413  *
414  * Returns: the byte string contained within the attribute or %NULL.
415  */
416 const char *
417 _g_file_attribute_value_get_byte_string (const GFileAttributeValue *attr)
418 {
419   if (attr == NULL)
420     return NULL;
421
422   g_return_val_if_fail (attr->type == G_FILE_ATTRIBUTE_TYPE_BYTE_STRING, NULL);
423
424   return attr->u.string;
425 }
426
427 char **
428 _g_file_attribute_value_get_stringv (const GFileAttributeValue *attr)
429 {
430   if (attr == NULL)
431     return NULL;
432
433   g_return_val_if_fail (attr->type == G_FILE_ATTRIBUTE_TYPE_STRINGV, NULL);
434
435   return attr->u.stringv;
436 }
437
438 /*
439  * _g_file_attribute_value_get_boolean:
440  * @attr: a #GFileAttributeValue.
441  *
442  * Gets the boolean value from a file attribute value. If the value is not the
443  * right type then %FALSE will be returned.
444  *
445  * Returns: the boolean value contained within the attribute, or %FALSE.
446  */
447 gboolean
448 _g_file_attribute_value_get_boolean (const GFileAttributeValue *attr)
449 {
450   if (attr == NULL)
451     return FALSE;
452
453   g_return_val_if_fail (attr->type == G_FILE_ATTRIBUTE_TYPE_BOOLEAN, FALSE);
454
455   return attr->u.boolean;
456 }
457
458 /*
459  * _g_file_attribute_value_get_uint32:
460  * @attr: a #GFileAttributeValue.
461  *
462  * Gets the unsigned 32-bit integer from a file attribute value. If the value
463  * is not the right type then 0 will be returned.
464  *
465  * Returns: the unsigned 32-bit integer from the attribute, or 0.
466  */
467 guint32
468 _g_file_attribute_value_get_uint32 (const GFileAttributeValue *attr)
469 {
470   if (attr == NULL)
471     return 0;
472
473   g_return_val_if_fail (attr->type == G_FILE_ATTRIBUTE_TYPE_UINT32, 0);
474
475   return attr->u.uint32;
476 }
477
478 /*
479  * _g_file_attribute_value_get_int32:
480  * @attr: a #GFileAttributeValue.
481  *
482  * Gets the signed 32-bit integer from a file attribute value. If the value
483  * is not the right type then 0 will be returned.
484  *
485  * Returns: the signed 32-bit integer from the attribute, or 0.
486  */
487 gint32
488 _g_file_attribute_value_get_int32 (const GFileAttributeValue *attr)
489 {
490   if (attr == NULL)
491     return 0;
492
493   g_return_val_if_fail (attr->type == G_FILE_ATTRIBUTE_TYPE_INT32, 0);
494
495   return attr->u.int32;
496 }
497
498 /*
499  * _g_file_attribute_value_get_uint64:
500  * @attr: a #GFileAttributeValue.
501  *
502  * Gets the unsigned 64-bit integer from a file attribute value. If the value
503  * is not the right type then 0 will be returned.
504  *
505  * Returns: the unsigned 64-bit integer from the attribute, or 0.
506  */
507 guint64
508 _g_file_attribute_value_get_uint64 (const GFileAttributeValue *attr)
509 {
510   if (attr == NULL)
511     return 0;
512
513   g_return_val_if_fail (attr->type == G_FILE_ATTRIBUTE_TYPE_UINT64, 0);
514
515   return attr->u.uint64;
516 }
517
518 /*
519  * _g_file_attribute_value_get_int64:
520  * @attr: a #GFileAttributeValue.
521  *
522  * Gets the signed 64-bit integer from a file attribute value. If the value
523  * is not the right type then 0 will be returned.
524  *
525  * Returns: the signed 64-bit integer from the attribute, or 0.
526  */
527 gint64
528 _g_file_attribute_value_get_int64 (const GFileAttributeValue *attr)
529 {
530   if (attr == NULL)
531     return 0;
532
533   g_return_val_if_fail (attr->type == G_FILE_ATTRIBUTE_TYPE_INT64, 0);
534
535   return attr->u.int64;
536 }
537
538 /*
539  * _g_file_attribute_value_get_object:
540  * @attr: a #GFileAttributeValue.
541  *
542  * Gets the GObject from a file attribute value. If the value
543  * is not the right type then %NULL will be returned.
544  *
545  * Returns: the GObject from the attribute, or %NULL.
546  **/
547 GObject *
548 _g_file_attribute_value_get_object (const GFileAttributeValue *attr)
549 {
550   if (attr == NULL)
551     return NULL;
552
553   g_return_val_if_fail (attr->type == G_FILE_ATTRIBUTE_TYPE_OBJECT, NULL);
554
555   return attr->u.obj;
556 }
557
558
559 void
560 _g_file_attribute_value_set_from_pointer (GFileAttributeValue *value,
561                                           GFileAttributeType   type,
562                                           gpointer             value_p,
563                                           gboolean             dup)
564 {
565   _g_file_attribute_value_clear (value);
566   value->type = type;
567   switch (type)
568     {
569     case G_FILE_ATTRIBUTE_TYPE_STRING:
570     case G_FILE_ATTRIBUTE_TYPE_BYTE_STRING:
571       if (dup)
572         value->u.string = g_strdup (value_p);
573       else
574         value->u.string = value_p;
575       break;
576
577     case G_FILE_ATTRIBUTE_TYPE_STRINGV:
578       if (dup)
579         value->u.stringv = g_strdupv (value_p);
580       else
581         value->u.stringv = value_p;
582       break;
583
584     case G_FILE_ATTRIBUTE_TYPE_OBJECT:
585       if (dup)
586         value->u.obj = g_object_ref (value_p);
587       else
588         value->u.obj = value_p;
589       break;
590
591     case G_FILE_ATTRIBUTE_TYPE_BOOLEAN:
592       value->u.boolean = *(gboolean *)value_p;
593       break;
594
595     case G_FILE_ATTRIBUTE_TYPE_UINT32:
596       value->u.uint32 = *(guint32 *)value_p;
597       break;
598
599     case G_FILE_ATTRIBUTE_TYPE_INT32:
600       value->u.int32 = *(gint32 *)value_p;
601       break;
602
603     case G_FILE_ATTRIBUTE_TYPE_UINT64:
604       value->u.uint64 = *(guint64 *)value_p;
605       break;
606
607     case G_FILE_ATTRIBUTE_TYPE_INT64:
608       value->u.int64 = *(gint64 *)value_p;
609       break;
610
611     case G_FILE_ATTRIBUTE_TYPE_INVALID:
612       break;
613
614     default:
615       g_warning ("Unknown type specified in g_file_info_set_attribute\n");
616       break;
617     }
618 }
619
620 /*
621  * _g_file_attribute_value_set_string:
622  * @attr: a #GFileAttributeValue.
623  * @string: a UTF-8 string to set within the type.
624  *
625  * Sets the attribute value to a given UTF-8 string.
626  */
627 void
628 _g_file_attribute_value_set_string (GFileAttributeValue *attr,
629                                     const char          *string)
630 {
631   g_return_if_fail (attr != NULL);
632   g_return_if_fail (string != NULL);
633
634   _g_file_attribute_value_clear (attr);
635   attr->type = G_FILE_ATTRIBUTE_TYPE_STRING;
636   attr->u.string = g_strdup (string);
637 }
638
639 /*
640  * _g_file_attribute_value_set_byte_string:
641  * @attr: a #GFileAttributeValue.
642  * @string: a byte string to set within the type.
643  *
644  * Sets the attribute value to a given byte string.
645  */
646 void
647 _g_file_attribute_value_set_byte_string (GFileAttributeValue *attr,
648                                          const char          *string)
649 {
650   g_return_if_fail (attr != NULL);
651   g_return_if_fail (string != NULL);
652
653   _g_file_attribute_value_clear (attr);
654   attr->type = G_FILE_ATTRIBUTE_TYPE_BYTE_STRING;
655   attr->u.string = g_strdup (string);
656 }
657
658 void
659 _g_file_attribute_value_set_stringv (GFileAttributeValue *attr,
660                                      char               **value)
661 {
662   g_return_if_fail (attr != NULL);
663   g_return_if_fail (value != NULL);
664
665   _g_file_attribute_value_clear (attr);
666   attr->type = G_FILE_ATTRIBUTE_TYPE_STRINGV;
667   attr->u.stringv = g_strdupv (value);
668 }
669
670
671 /*
672  * _g_file_attribute_value_set_boolean:
673  * @attr: a #GFileAttributeValue.
674  * @value: a #gboolean to set within the type.
675  *
676  * Sets the attribute value to the given boolean value.
677  */
678 void
679 _g_file_attribute_value_set_boolean (GFileAttributeValue *attr,
680                                      gboolean             value)
681 {
682   g_return_if_fail (attr != NULL);
683
684   _g_file_attribute_value_clear (attr);
685   attr->type = G_FILE_ATTRIBUTE_TYPE_BOOLEAN;
686   attr->u.boolean = !!value;
687 }
688
689 /*
690  * _g_file_attribute_value_set_uint32:
691  * @attr: a #GFileAttributeValue.
692  * @value: a #guint32 to set within the type.
693  *
694  * Sets the attribute value to the given unsigned 32-bit integer.
695  */
696 void
697 _g_file_attribute_value_set_uint32 (GFileAttributeValue *attr,
698                                     guint32              value)
699 {
700   g_return_if_fail (attr != NULL);
701
702   _g_file_attribute_value_clear (attr);
703   attr->type = G_FILE_ATTRIBUTE_TYPE_UINT32;
704   attr->u.uint32 = value;
705 }
706
707 /*
708  * _g_file_attribute_value_set_int32:
709  * @attr: a #GFileAttributeValue.
710  * @value: a #gint32 to set within the type.
711  *
712  * Sets the attribute value to the given signed 32-bit integer.
713  */
714 void
715 _g_file_attribute_value_set_int32 (GFileAttributeValue *attr,
716                                    gint32               value)
717 {
718   g_return_if_fail (attr != NULL);
719
720   _g_file_attribute_value_clear (attr);
721   attr->type = G_FILE_ATTRIBUTE_TYPE_INT32;
722   attr->u.int32 = value;
723 }
724
725 /*
726  * _g_file_attribute_value_set_uint64:
727  * @attr: a #GFileAttributeValue.
728  * @value: a #guint64 to set within the type.
729  *
730  * Sets the attribute value to a given unsigned 64-bit integer.
731  */
732 void
733 _g_file_attribute_value_set_uint64 (GFileAttributeValue *attr,
734                                     guint64              value)
735 {
736   g_return_if_fail (attr != NULL);
737
738   _g_file_attribute_value_clear (attr);
739   attr->type = G_FILE_ATTRIBUTE_TYPE_UINT64;
740   attr->u.uint64 = value;
741 }
742
743 /*
744  * _g_file_attribute_value_set_int64:
745  * @attr: a #GFileAttributeValue.
746  * @value: a #gint64 to set within the type.
747  *
748  * Sets the attribute value to a given signed 64-bit integer.
749  */
750 void
751 _g_file_attribute_value_set_int64 (GFileAttributeValue *attr,
752                                    gint64               value)
753 {
754   g_return_if_fail (attr != NULL);
755
756   _g_file_attribute_value_clear (attr);
757   attr->type = G_FILE_ATTRIBUTE_TYPE_INT64;
758   attr->u.int64 = value;
759 }
760
761 /*
762  * _g_file_attribute_value_set_object:
763  * @attr: a #GFileAttributeValue.
764  * @obj: a #GObject.
765  *
766  * Sets the attribute to contain the value @obj.
767  * The @attr references the GObject internally.
768  */
769 void
770 _g_file_attribute_value_set_object (GFileAttributeValue *attr,
771                                     GObject             *obj)
772 {
773   g_return_if_fail (attr != NULL);
774   g_return_if_fail (obj != NULL);
775
776   _g_file_attribute_value_clear (attr);
777   attr->type = G_FILE_ATTRIBUTE_TYPE_OBJECT;
778   attr->u.obj = g_object_ref (obj);
779 }
780
781 typedef struct {
782   GFileAttributeInfoList public;
783   GArray *array;
784   int ref_count;
785 } GFileAttributeInfoListPriv;
786
787 static void
788 list_update_public (GFileAttributeInfoListPriv *priv)
789 {
790   priv->public.infos = (GFileAttributeInfo *)priv->array->data;
791   priv->public.n_infos = priv->array->len;
792 }
793
794 /**
795  * g_file_attribute_info_list_new:
796  *
797  * Creates a new file attribute info list.
798  *
799  * Returns: a #GFileAttributeInfoList.
800  */
801 GFileAttributeInfoList *
802 g_file_attribute_info_list_new (void)
803 {
804   GFileAttributeInfoListPriv *priv;
805
806   priv = g_new0 (GFileAttributeInfoListPriv, 1);
807
808   priv->ref_count = 1;
809   priv->array = g_array_new (TRUE, FALSE, sizeof (GFileAttributeInfo));
810
811   list_update_public (priv);
812
813   return (GFileAttributeInfoList *)priv;
814 }
815
816 /**
817  * g_file_attribute_info_list_dup:
818  * @list: a #GFileAttributeInfoList to duplicate.
819  *
820  * Makes a duplicate of a file attribute info list.
821  *
822  * Returns: a copy of the given @list.
823  */
824 GFileAttributeInfoList *
825 g_file_attribute_info_list_dup (GFileAttributeInfoList *list)
826 {
827   GFileAttributeInfoListPriv *new;
828   int i;
829
830   g_return_val_if_fail (list != NULL, NULL);
831
832   new = g_new0 (GFileAttributeInfoListPriv, 1);
833   new->ref_count = 1;
834   new->array = g_array_new (TRUE, FALSE, sizeof (GFileAttributeInfo));
835
836   g_array_set_size (new->array, list->n_infos);
837   list_update_public (new);
838   for (i = 0; i < list->n_infos; i++)
839     {
840       new->public.infos[i].name = g_strdup (list->infos[i].name);
841       new->public.infos[i].type = list->infos[i].type;
842       new->public.infos[i].flags = list->infos[i].flags;
843     }
844
845   return (GFileAttributeInfoList *)new;
846 }
847
848 /**
849  * g_file_attribute_info_list_ref:
850  * @list: a #GFileAttributeInfoList to reference.
851  *
852  * References a file attribute info list.
853  *
854  * Returns: #GFileAttributeInfoList or %NULL on error.
855  */
856 GFileAttributeInfoList *
857 g_file_attribute_info_list_ref (GFileAttributeInfoList *list)
858 {
859   GFileAttributeInfoListPriv *priv = (GFileAttributeInfoListPriv *)list;
860
861   g_return_val_if_fail (list != NULL, NULL);
862   g_return_val_if_fail (priv->ref_count > 0, NULL);
863
864   g_atomic_int_inc (&priv->ref_count);
865
866   return list;
867 }
868
869 /**
870  * g_file_attribute_info_list_unref:
871  * @list: The #GFileAttributeInfoList to unreference.
872  *
873  * Removes a reference from the given @list. If the reference count
874  * falls to zero, the @list is deleted.
875  */
876 void
877 g_file_attribute_info_list_unref (GFileAttributeInfoList *list)
878 {
879   GFileAttributeInfoListPriv *priv = (GFileAttributeInfoListPriv *)list;
880   int i;
881
882   g_return_if_fail (list != NULL);
883   g_return_if_fail (priv->ref_count > 0);
884
885   if (g_atomic_int_dec_and_test (&priv->ref_count))
886     {
887       for (i = 0; i < list->n_infos; i++)
888         g_free (list->infos[i].name);
889       g_array_free (priv->array, TRUE);
890       g_free (list);
891     }
892 }
893
894 static int
895 g_file_attribute_info_list_bsearch (GFileAttributeInfoList *list,
896                                     const char             *name)
897 {
898   int start, end, mid;
899
900   start = 0;
901   end = list->n_infos;
902
903   while (start != end)
904     {
905       mid = start + (end - start) / 2;
906
907       if (strcmp (name, list->infos[mid].name) < 0)
908         end = mid;
909       else if (strcmp (name, list->infos[mid].name) > 0)
910         start = mid + 1;
911       else
912         return mid;
913     }
914   return start;
915 }
916
917 /**
918  * g_file_attribute_info_list_lookup:
919  * @list: a #GFileAttributeInfoList.
920  * @name: the name of the attribute to lookup.
921  *
922  * Gets the file attribute with the name @name from @list.
923  *
924  * Returns: a #GFileAttributeInfo for the @name, or %NULL if an
925  * attribute isn't found.
926  */
927 const GFileAttributeInfo *
928 g_file_attribute_info_list_lookup (GFileAttributeInfoList *list,
929                                    const char             *name)
930 {
931   int i;
932
933   g_return_val_if_fail (list != NULL, NULL);
934   g_return_val_if_fail (name != NULL, NULL);
935
936   i = g_file_attribute_info_list_bsearch (list, name);
937
938   if (i < list->n_infos && strcmp (list->infos[i].name, name) == 0)
939     return &list->infos[i];
940
941   return NULL;
942 }
943
944 /**
945  * g_file_attribute_info_list_add:
946  * @list: a #GFileAttributeInfoList.
947  * @name: the name of the attribute to add.
948  * @type: the #GFileAttributeType for the attribute.
949  * @flags: #GFileAttributeInfoFlags for the attribute.
950  *
951  * Adds a new attribute with @name to the @list, setting
952  * its @type and @flags.
953  */
954 void
955 g_file_attribute_info_list_add (GFileAttributeInfoList *list,
956                                 const char             *name,
957                                 GFileAttributeType      type,
958                                 GFileAttributeInfoFlags flags)
959 {
960   GFileAttributeInfoListPriv *priv = (GFileAttributeInfoListPriv *)list;
961   GFileAttributeInfo info;
962   int i;
963
964   g_return_if_fail (list != NULL);
965   g_return_if_fail (name != NULL);
966
967   i = g_file_attribute_info_list_bsearch (list, name);
968
969   if (i < list->n_infos && strcmp (list->infos[i].name, name) == 0)
970     {
971       list->infos[i].type = type;
972       return;
973     }
974
975   info.name = g_strdup (name);
976   info.type = type;
977   info.flags = flags;
978   g_array_insert_vals (priv->array, i, &info, 1);
979
980   list_update_public (priv);
981 }