Bumps documentation to 93% symbol coverage, touching most
[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, write to the
17  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18  * Boston, MA 02111-1307, USA.
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 <glib-object.h>
29 #include "glibintl.h"
30
31 /**
32  * SECTION:gfileattribute
33  * @short_description: Key-Value Paired File Attributes.
34  * @see_also: #GFile, #GFileInfo.
35  * 
36  * File attributes in GIO consist of a list of key-value pairs. 
37  * 
38  * Keys are strings that contain a key namespace and a key name, separated
39  * by a colon, e.g. "namespace:keyname". Namespaces are included to sort
40  * key-value pairs by namespaces for relevance. Keys can be searched 
41  * for using wildcards, e.g. "std:*" will return all of the keys in the 
42  * "std" namespace.
43  * 
44  * Values are stored within the list in #GFileAttributeValue structures.
45  * Values can store different types, listed in the enum #GFileAttributeType.
46  * Upon creation of a #GFileAttributeValue, the type will be set to 
47  * %G_FILE_ATTRIBUTE_TYPE_INVALID. 
48  * 
49  * The Key-value list is stored within the #GFile structure as a 
50  * #GFileAttributeInfoList. This list is queryable by key names 
51  * as indicated earlier.
52  * 
53  * Classes that implement #GFileIface will create a #GFileAttributeInfoList and 
54  * install default keys and values for their given file system, architecture, 
55  * and other possible implementation details (e.g., on a UNIX system, a file 
56  * attribute key will be registered for the user id for a given file). Other 
57  * attributes can be appended to a #GFileAttributeList later by 
58  * g_file_attribute_info_list_add(). 
59  * 
60  * <para>
61  * <table>
62  * <title>GFileAttributes Namespaces</title>
63  * <tgroup cols='2' align='left'><thead>
64  * <row><entry>Namspace</entry><entry>Description</entry></row>
65  * </thead>
66  * <tbody>
67  * <row><entry>"std"</entry><entry>The "Standard" namespace. General file
68  * information that any application may need should be put in this namespace. Examples
69  * include the file's name, type, and size.</entry></row> 
70  * <row><entry>"etag"</entry><entry>The "Entity Tag" namespace. Remotely shared
71  * files, like those on HTTP/1.1 file systems, use "entity tags" to quickly determine 
72  * if a file has been modified. Entity tags are globally unique, and should
73  * always be sent with the current revision of a file. An example of a key
74  * in this namespace is "value", which contains the value of the current
75  * entity tag.</entry></row>
76  * <row><entry>"id"</entry><entry>The "Identification" namespace. This 
77  * namespace is used by file managers and applications that list directories
78  * to check for loops and to uniquely identify files.</entry></row>
79  * <row><entry>"access"</entry><entry>The "Access" namespace. Used to check
80  * if a user has the proper privilidges to access files and perform
81  * file operations. Keys in this namespace are made to be generic 
82  * and easily understood, e.g. the "can_read" key is %TRUE if 
83  * the current user has permission to read the file. UNIX permissions and
84  * NTFS ACLs in Windows should be mapped to these values.</entry></row>
85  * <row><entry>"mountable"</entry><entry>The "Mountable" namespace. Includes 
86  * simple boolean keys for checking if a file or path supports mount operations, e.g.
87  * mount, unmount, eject.</entry></row>
88  * <row><entry>"time"</entry><entry>The "Time" namespace. Includes file 
89  * access, changed, created times. </entry></row>
90  * <row><entry>"unix"</entry><entry>The "Unix" namespace. Includes UNIX-specific
91  * information and may not be available for all files. Examples include 
92  * the UNIX "UID", "GID", etc.</entry></row>
93  * <row><entry>"dos"</entry><entry>The "DOS" namespace. Includes DOS-specific 
94  * information and may not be available for all files. Examples include
95  * "is_system" for checking if a file is marked as a system file, and "is_archive"
96  * for checking if a file is marked as an archive file.</entry></row>
97  * <row><entry>"owner"</entry><entry>The "Owner" namespace. Includes information
98  * about who owns a file. May not be available for all file systems. Examples include
99  * "user" for getting the user name of the file owner.</entry></row>
100  * <row><entry>"thumbnail"</entry><entry>The "Thumbnail" namespace. Includes 
101  * information about file thumbnails and their location within the file system. Exaples of 
102  * keys in this namespace include "path" to get the location of a thumbnail, and "failed"
103  * to check if thumbnailing failed.</entry></row>
104  * <row><entry>"fs"</entry><entry>The "Filesystem" namespace. Gets information
105  * about the file system where a file is located, such as its type, how much
106  * space is left available, and the overall size of the file system.</entry></row>
107  * <row><entry>"gvfs"</entry><entry>The "GVFS" namespace. Keys in this namespace
108  * contain information about the current GVFS backend in use. </entry></row>
109  * </tbody>
110  * </tgroup>
111  * </table>
112  * </para>
113  * 
114  * More namespaces can be added from GIO modules or by individual applications. 
115  * For more information about writing GIO modules, see #GIOModule.
116  * 
117  * <para><table>
118  * <title>GFileAttributes Built-in Keys and Value Types</title>
119  * <tgroup cols='3' align='left'><thead>
120  * <row><entry>Enum Value</entry><entry>Namespace:Key</entry><entry>Value Type</entry></row>
121  * </thead><tbody>
122  * <row><entry>%G_FILE_ATTRIBUTE_STD_TYPE</entry><entry>std:type</entry><entry>uint32 (#GFileType)</entry></row>
123  * <row><entry>%G_FILE_ATTRIBUTE_STD_IS_HIDDEN</entry><entry>std:is_hidden</entry><entry>boolean</entry></row>
124  * <row><entry>%G_FILE_ATTRIBUTE_STD_IS_BACKUP</entry><entry>std:is_backup</entry><entry>boolean</entry></row>
125  * <row><entry>%G_FILE_ATTRIBUTE_STD_IS_SYMLINK</entry><entry>std:is_symlink</entry><entry>boolean</entry></row>
126  * <row><entry>%G_FILE_ATTRIBUTE_STD_IS_VIRTUAL</entry><entry>std:is_virtual</entry><entry>boolean</entry></row>
127  * <row><entry>%G_FILE_ATTRIBUTE_STD_NAME</entry><entry>std:name</entry><entry>byte string</entry></row>
128  * <row><entry>%G_FILE_ATTRIBUTE_STD_DISPLAY_NAME</entry><entry>std:display_name</entry><entry>string</entry></row>
129  * <row><entry>%G_FILE_ATTRIBUTE_STD_EDIT_NAME</entry><entry>std:edit_name</entry><entry>string</entry></row>
130  * <row><entry>%G_FILE_ATTRIBUTE_STD_ICON</entry><entry>std:icon</entry><entry>object (#GIcon)</entry></row>
131  * <row><entry>%G_FILE_ATTRIBUTE_STD_CONTENT_TYPE</entry><entry>std:content_type</entry><entry>string</entry></row>
132  * <row><entry>%G_FILE_ATTRIBUTE_STD_FAST_CONTENT_TYPE</entry><entry>std:fast_content_type</entry><entry>string</entry></row>
133  * <row><entry>%G_FILE_ATTRIBUTE_STD_SIZE</entry><entry>std:size</entry><entry>uint64</entry></row>
134  * <row><entry>%G_FILE_ATTRIBUTE_STD_SYMLINK_TARGET</entry><entry>std:symlink_target</entry><entry>byte string</entry></row>
135  * <row><entry>%G_FILE_ATTRIBUTE_STD_TARGET_URI</entry><entry>std:target_uri</entry><entry>string</entry></row>
136  * <row><entry>%G_FILE_ATTRIBUTE_STD_SORT_ORDER</entry><entry>std:sort_order</entry><entry>int32</entry></row>
137  * <row><entry>%G_FILE_ATTRIBUTE_ETAG_VALUE</entry><entry>etag:value</entry><entry>string</entry></row>
138  * <row><entry>%G_FILE_ATTRIBUTE_ID_FILE</entry><entry>id:file</entry><entry>string</entry></row>
139  * <row><entry>%G_FILE_ATTRIBUTE_ID_FS</entry><entry>id:fs</entry><entry>string</entry></row>
140  * <row><entry>%G_FILE_ATTRIBUTE_ACCESS_CAN_READ</entry><entry>access:can_read</entry><entry>boolean</entry></row>
141  * <row><entry>%G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE</entry><entry>access:can_write</entry><entry>boolean</entry></row>
142  * <row><entry>%G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE</entry><entry>access:can_execute</entry><entry>boolean</entry></row>
143  * <row><entry>%G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE</entry><entry>access:can_delete</entry><entry>boolean</entry></row>
144  * <row><entry>%G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH</entry><entry>access:can_trash</entry><entry>boolean</entry></row>
145  * <row><entry>%G_FILE_ATTRIBUTE_ACCESS_CAN_RENAME</entry><entry>access:can_rename</entry><entry>boolean</entry></row>
146  * <row><entry>%G_FILE_ATTRIBUTE_MOUNTABLE_CAN_MOUNT</entry><entry>mountable:can_mount</entry><entry>boolean</entry></row>
147  * <row><entry>%G_FILE_ATTRIBUTE_MOUNTABLE_CAN_UNMOUNT</entry><entry>mountable:can_unmount</entry><entry>boolean</entry></row>
148  * <row><entry>%G_FILE_ATTRIBUTE_MOUNTABLE_CAN_EJECT</entry><entry>mountable:can_eject</entry><entry>boolean</entry></row>
149  * <row><entry>%G_FILE_ATTRIBUTE_MOUNTABLE_UNIX_DEVICE</entry><entry>mountable:unix_device</entry><entry>uint32</entry></row>
150  * <row><entry>%G_FILE_ATTRIBUTE_MOUNTABLE_HAL_UDI</entry><entry>mountable:hal_udi</entry><entry>string</entry></row>
151  * <row><entry>%G_FILE_ATTRIBUTE_TIME_MODIFIED</entry><entry>time:modified</entry><entry>uint64</entry></row>
152  * <row><entry>%G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC</entry><entry>time:modified_usec</entry><entry>uint32</entry></row>
153  * <row><entry>%G_FILE_ATTRIBUTE_TIME_ACCESS</entry><entry>time:access</entry><entry>uint64</entry></row>
154  * <row><entry>%G_FILE_ATTRIBUTE_TIME_ACCESS_USEC</entry><entry>time:access_usec</entry><entry>uint32</entry></row>
155  * <row><entry>%G_FILE_ATTRIBUTE_TIME_CHANGED</entry><entry>time:changed</entry><entry>uint64</entry></row>
156  * <row><entry>%G_FILE_ATTRIBUTE_TIME_CHANGED_USEC</entry><entry>time:changed_usec</entry><entry>uint32</entry></row>
157  * <row><entry>%G_FILE_ATTRIBUTE_TIME_CREATED</entry><entry>time:created</entry><entry>uint64</entry></row>
158  * <row><entry>%G_FILE_ATTRIBUTE_TIME_CREATED_USEC</entry><entry>time:created_usec</entry><entry>uint32</entry></row>
159  * <row><entry>%G_FILE_ATTRIBUTE_UNIX_DEVICE</entry><entry>unix:device</entry><entry>uint32</entry></row>
160  * <row><entry>%G_FILE_ATTRIBUTE_UNIX_INODE</entry><entry>unix:inode</entry><entry>uint64</entry></row>
161  * <row><entry>%G_FILE_ATTRIBUTE_UNIX_MODE</entry><entry>unix:mode</entry><entry>uint32</entry></row>
162  * <row><entry>%G_FILE_ATTRIBUTE_UNIX_NLINK</entry><entry>unix:nlink</entry><entry>uint32</entry></row>
163  * <row><entry>%G_FILE_ATTRIBUTE_UNIX_UID</entry><entry>unix:uid</entry><entry>uint32</entry></row>
164  * <row><entry>%G_FILE_ATTRIBUTE_UNIX_GID</entry><entry>unix:gid</entry><entry>uint32</entry></row>
165  * <row><entry>%G_FILE_ATTRIBUTE_UNIX_RDEV</entry><entry>unix:rdev</entry><entry>uint32</entry></row>
166  * <row><entry>%G_FILE_ATTRIBUTE_UNIX_BLOCK_SIZE</entry><entry>unix:block_size</entry><entry>uint32</entry></row>
167  * <row><entry>%G_FILE_ATTRIBUTE_UNIX_BLOCKS</entry><entry>unix:blocks</entry><entry>uint64</entry></row>
168  * <row><entry>%G_FILE_ATTRIBUTE_UNIX_IS_MOUNTPOINT</entry><entry>unix:is_mountpoint</entry><entry>boolean</entry></row>
169  * <row><entry>%G_FILE_ATTRIBUTE_DOS_IS_ARCHIVE</entry><entry>dos:is_archive</entry><entry>boolean</entry></row>
170  * <row><entry>%G_FILE_ATTRIBUTE_DOS_IS_SYSTEM</entry><entry>dos:is_system</entry><entry>boolean</entry></row>
171  * <row><entry>%G_FILE_ATTRIBUTE_OWNER_USER</entry><entry>owner:user</entry><entry>string</entry></row>
172  * <row><entry>%G_FILE_ATTRIBUTE_OWNER_USER_REAL</entry><entry>owner:user_real</entry><entry>string</entry></row>
173  * <row><entry>%G_FILE_ATTRIBUTE_OWNER_GROUP</entry><entry>owner:group</entry><entry>string</entry></row>
174  * <row><entry>%G_FILE_ATTRIBUTE_THUMBNAIL_PATH</entry><entry>thumbnail:path</entry><entry>bytestring</entry></row>
175  * <row><entry>%G_FILE_ATTRIBUTE_THUMBNAILING_FAILED</entry><entry>thumbnail:failed</entry><entry>boolean</entry></row>
176  * <row><entry>%G_FILE_ATTRIBUTE_FS_SIZE</entry><entry>fs:size</entry><entry>uint64</entry></row>
177  * <row><entry>%G_FILE_ATTRIBUTE_FS_FREE</entry><entry>fs:free</entry><entry>uint64</entry></row>
178  * <row><entry>%G_FILE_ATTRIBUTE_FS_TYPE</entry><entry>fs:type</entry><entry>string</entry></row>
179  * <row><entry>%G_FILE_ATTRIBUTE_FS_READONLY</entry><entry>fs:readonly</entry><entry>boolean</entry></row>
180  * <row><entry>%G_FILE_ATTRIBUTE_GVFS_BACKEND</entry><entry>gvfs:backend</entry><entry>string</entry></row>
181  * </tbody></tgroup></table></para>
182  *  
183  **/ 
184
185 /**
186  * g_file_attribute_value_free:
187  * @attr: a #GFileAttributeValue. 
188  * 
189  * Frees the memory used by @attr.
190  *
191  **/
192 void
193 g_file_attribute_value_free (GFileAttributeValue *attr)
194 {
195   g_return_if_fail (attr != NULL);
196
197   g_file_attribute_value_clear (attr);
198   g_free (attr);
199 }
200
201 /**
202  * g_file_attribute_value_clear:
203  * @attr: a #GFileAttributeValue.
204  *
205  * Clears the value of @attr and sets its type to 
206  * %G_FILE_ATTRIBUTE_TYPE_INVALID.
207  * 
208  **/
209 void
210 g_file_attribute_value_clear (GFileAttributeValue *attr)
211 {
212   g_return_if_fail (attr != NULL);
213
214   if (attr->type == G_FILE_ATTRIBUTE_TYPE_STRING ||
215       attr->type == G_FILE_ATTRIBUTE_TYPE_BYTE_STRING)
216     g_free (attr->u.string);
217   
218   if (attr->type == G_FILE_ATTRIBUTE_TYPE_OBJECT &&
219       attr->u.obj != NULL)
220     g_object_unref (attr->u.obj);
221   
222   attr->type = G_FILE_ATTRIBUTE_TYPE_INVALID;
223 }
224
225 /**
226  * g_file_attribute_value_set:
227  * @attr: a #GFileAttributeValue to set the value in.
228  * @new_value: a #GFileAttributeValue to get the value from.
229  * 
230  * Sets an attribute's value from another attribute.
231  **/
232 void
233 g_file_attribute_value_set (GFileAttributeValue *attr,
234                             const GFileAttributeValue *new_value)
235 {
236   g_return_if_fail (attr != NULL);
237   g_return_if_fail (new_value != NULL);
238
239   g_file_attribute_value_clear (attr);
240   *attr = *new_value;
241
242   if (attr->type == G_FILE_ATTRIBUTE_TYPE_STRING ||
243       attr->type == G_FILE_ATTRIBUTE_TYPE_BYTE_STRING)
244     attr->u.string = g_strdup (attr->u.string);
245   
246   if (attr->type == G_FILE_ATTRIBUTE_TYPE_OBJECT &&
247       attr->u.obj != NULL)
248     g_object_ref (attr->u.obj);
249 }
250
251 /**
252  * g_file_attribute_value_new:
253  * 
254  * Creates a new file attribute.
255  * 
256  * Returns: a #GFileAttributeValue.
257  **/
258 GFileAttributeValue *
259 g_file_attribute_value_new (void)
260 {
261   GFileAttributeValue *attr;
262
263   attr = g_new (GFileAttributeValue, 1);
264   attr->type = G_FILE_ATTRIBUTE_TYPE_INVALID;
265   return attr;
266 }
267
268
269 /**
270  * g_file_attribute_value_dup:
271  * @other: a #GFileAttributeValue to duplicate.
272  * 
273  * Duplicates a file attribute.
274  * 
275  * Returns: a duplicate of the @other.
276  **/
277 GFileAttributeValue *
278 g_file_attribute_value_dup (const GFileAttributeValue *other)
279 {
280   GFileAttributeValue *attr;
281
282   g_return_val_if_fail (other != NULL, NULL);
283
284   attr = g_new (GFileAttributeValue, 1);
285   attr->type = G_FILE_ATTRIBUTE_TYPE_INVALID;
286   g_file_attribute_value_set (attr, other);
287   return attr;
288 }
289
290 static gboolean
291 valid_char (char c)
292 {
293   return c >= 32 && c <= 126 && c != '\\';
294 }
295
296 static char *
297 escape_byte_string (const char *str)
298 {
299   size_t len;
300   int num_invalid, i;
301   char *escaped_val, *p;
302   unsigned char c;
303   char *hex_digits = "0123456789abcdef";
304   
305   len = strlen (str);
306   
307   num_invalid = 0;
308   for (i = 0; i < len; i++)
309     {
310       if (!valid_char (str[i]))
311         num_invalid++;
312     }
313         
314   if (num_invalid == 0)
315     return g_strdup (str);
316   else
317     {
318       escaped_val = g_malloc (len + num_invalid*3 + 1);
319
320       p = escaped_val;
321       for (i = 0; i < len; i++)
322         {
323           c = str[i];
324           if (valid_char (c))
325             *p++ = c;
326           else
327             {
328               *p++ = '\\';
329               *p++ = 'x';
330               *p++ = hex_digits[(c >> 8) & 0xf];
331               *p++ = hex_digits[c & 0xf];
332             }
333         }
334       *p++ = 0;
335       return escaped_val;
336     }
337 }
338
339 /**
340  * g_file_attribute_value_as_string:
341  * @attr: a #GFileAttributeValue.
342  *
343  * Converts a #GFileAttributeValue to a string for display.
344  * The returned string should be freed when no longer needed.
345  * 
346  * Returns: a string from the @attr, %NULL on error, or "&lt;invalid&gt;" 
347  * if @attr is of type %G_FILE_ATTRIBUTE_TYPE_INVALID.
348  **/
349 char *
350 g_file_attribute_value_as_string (const GFileAttributeValue *attr)
351 {
352   char *str;
353
354   g_return_val_if_fail (attr != NULL, NULL);
355
356   switch (attr->type)
357     {
358     case G_FILE_ATTRIBUTE_TYPE_STRING:
359       str = g_strdup (attr->u.string);
360       break;
361     case G_FILE_ATTRIBUTE_TYPE_BYTE_STRING:
362       str = escape_byte_string (attr->u.string);
363       break;
364     case G_FILE_ATTRIBUTE_TYPE_BOOLEAN:
365       str = g_strdup_printf ("%s", attr->u.boolean?"TRUE":"FALSE");
366       break;
367     case G_FILE_ATTRIBUTE_TYPE_UINT32:
368       str = g_strdup_printf ("%u", (unsigned int)attr->u.uint32);
369       break;
370     case G_FILE_ATTRIBUTE_TYPE_INT32:
371       str = g_strdup_printf ("%i", (int)attr->u.int32);
372       break;
373     case G_FILE_ATTRIBUTE_TYPE_UINT64:
374       str = g_strdup_printf ("%"G_GUINT64_FORMAT, attr->u.uint64);
375       break;
376     case G_FILE_ATTRIBUTE_TYPE_INT64:
377       str = g_strdup_printf ("%"G_GINT64_FORMAT, attr->u.int64);
378       break;
379     case G_FILE_ATTRIBUTE_TYPE_OBJECT:
380       str = g_strdup_printf ("%s:%p", g_type_name_from_instance
381                                           ((GTypeInstance *) attr->u.obj),
382                                       attr->u.obj);
383       break;
384     default:
385       g_warning ("Invalid type in GFileInfo attribute");
386       str = g_strdup ("<invalid>");
387       break;
388     }
389   
390   return str;
391 }
392
393 /**
394  * g_file_attribute_value_get_string:
395  * @attr: a #GFileAttributeValue.
396  * 
397  * Gets the string from a file attribute value. If the value is not the
398  * right type then %NULL will be returned.
399  * 
400  * Returns: the string value contained within the attribute, or %NULL.
401  **/
402 const char *
403 g_file_attribute_value_get_string (const GFileAttributeValue *attr)
404 {
405   if (attr == NULL)
406     return NULL;
407
408   g_return_val_if_fail (attr->type == G_FILE_ATTRIBUTE_TYPE_STRING, NULL);
409
410   return attr->u.string;
411 }
412
413 /**
414  * g_file_attribute_value_get_byte_string:
415  * @attr: a #GFileAttributeValue.
416  * 
417  * Gets the byte string from a file attribute value. If the value is not the
418  * right type then %NULL will be returned.
419  * 
420  * Returns: the byte string contained within the attribute or %NULL.
421  **/
422 const char *
423 g_file_attribute_value_get_byte_string (const GFileAttributeValue *attr)
424 {
425   if (attr == NULL)
426     return NULL;
427
428   g_return_val_if_fail (attr->type == G_FILE_ATTRIBUTE_TYPE_BYTE_STRING, NULL);
429
430   return attr->u.string;
431 }
432   
433 /**
434  * g_file_attribute_value_get_boolean:
435  * @attr: a #GFileAttributeValue.
436  * 
437  * Gets the boolean value from a file attribute value. If the value is not the
438  * right type then %FALSE will be returned.
439  * 
440  * Returns: the boolean value contained within the attribute, or %FALSE.
441  **/
442 gboolean
443 g_file_attribute_value_get_boolean (const GFileAttributeValue *attr)
444 {
445   if (attr == NULL)
446     return FALSE;
447
448   g_return_val_if_fail (attr->type == G_FILE_ATTRIBUTE_TYPE_BOOLEAN, FALSE);
449
450   return attr->u.boolean;
451 }
452   
453 /**
454  * g_file_attribute_value_get_uint32:
455  * @attr: a #GFileAttributeValue.
456  * 
457  * Gets the unsigned 32-bit integer from a file attribute value. If the value 
458  * is not the right type then %0 will be returned.
459  * 
460  * Returns: the unsigned 32-bit integer from the attribute, or %0.
461  **/
462 guint32
463 g_file_attribute_value_get_uint32 (const GFileAttributeValue *attr)
464 {
465   if (attr == NULL)
466     return 0;
467
468   g_return_val_if_fail (attr->type == G_FILE_ATTRIBUTE_TYPE_UINT32, 0);
469
470   return attr->u.uint32;
471 }
472
473 /**
474  * g_file_attribute_value_get_int32:
475  * @attr: a #GFileAttributeValue.
476  * 
477  * Gets the signed 32-bit integer from a file attribute value. If the value 
478  * is not the right type then %0 will be returned.
479  * 
480  * Returns: the signed 32-bit integer from the attribute, or %0.
481  **/
482 gint32
483 g_file_attribute_value_get_int32 (const GFileAttributeValue *attr)
484 {
485   if (attr == NULL)
486     return 0;
487
488   g_return_val_if_fail (attr->type == G_FILE_ATTRIBUTE_TYPE_INT32, 0);
489
490   return attr->u.int32;
491 }
492
493 /**
494  * g_file_attribute_value_get_uint64:
495  * @attr: a #GFileAttributeValue.
496  * 
497  * Gets the unsigned 64-bit integer from a file attribute value. If the value 
498  * is not the right type then %0 will be returned.
499  * 
500  * Returns: the unsigned 64-bit integer from the attribute, or %0.
501  **/  
502 guint64
503 g_file_attribute_value_get_uint64 (const GFileAttributeValue *attr)
504 {
505   if (attr == NULL)
506     return 0;
507
508   g_return_val_if_fail (attr->type == G_FILE_ATTRIBUTE_TYPE_UINT64, 0);
509
510   return attr->u.uint64;
511 }
512
513 /**
514  * g_file_attribute_value_get_int64:
515  * @attr: a #GFileAttributeValue.
516  * 
517  * Gets the signed 64-bit integer from a file attribute value. If the value 
518  * is not the right type then %0 will be returned.
519  * 
520  * Returns: the signed 64-bit integer from the attribute, or %0. 
521  **/
522 gint64
523 g_file_attribute_value_get_int64 (const GFileAttributeValue *attr)
524 {
525   if (attr == NULL)
526     return 0;
527
528   g_return_val_if_fail (attr->type == G_FILE_ATTRIBUTE_TYPE_INT64, 0);
529
530   return attr->u.int64;
531 }
532
533 /**
534  * g_file_attribute_value_get_object:
535  * @attr: a #GFileAttributeValue.
536  * 
537  * Gets the GObject from a file attribute value. If the value 
538  * is not the right type then %NULL will be returned.
539  * 
540  * Returns: the GObject from the attribute, or %0.
541  **/
542 GObject *
543 g_file_attribute_value_get_object (const GFileAttributeValue *attr)
544 {
545   if (attr == NULL)
546     return NULL;
547
548   g_return_val_if_fail (attr->type == G_FILE_ATTRIBUTE_TYPE_OBJECT, NULL);
549
550   return attr->u.obj;
551 }
552   
553 /**
554  * g_file_attribute_value_set_string:
555  * @attr: a #GFileAttributeValue.
556  * @string: a string to set within the type.
557  * 
558  * Sets the attribute value to a given string.
559  * 
560  **/
561 void
562 g_file_attribute_value_set_string (GFileAttributeValue *attr,
563                                    const char          *string)
564 {
565   g_return_if_fail (attr != NULL);
566   g_return_if_fail (string != NULL);
567
568   g_file_attribute_value_clear (attr);
569   attr->type = G_FILE_ATTRIBUTE_TYPE_STRING;
570   attr->u.string = g_strdup (string);
571 }
572
573 /**
574  * g_file_attribute_value_set_byte_string:
575  * @attr: a #GFileAttributeValue.
576  * @string: a byte string to set within the type.
577  * 
578  * Sets the attribute value to a given byte string.
579  * 
580  **/
581 void
582 g_file_attribute_value_set_byte_string (GFileAttributeValue *attr,
583                                         const char          *string)
584 {
585   g_return_if_fail (attr != NULL);
586   g_return_if_fail (string != NULL);
587
588   g_file_attribute_value_clear (attr);
589   attr->type = G_FILE_ATTRIBUTE_TYPE_BYTE_STRING;
590   attr->u.string = g_strdup (string);
591 }
592
593 /**
594  * g_file_attribute_value_set_boolean:
595  * @attr: a #GFileAttributeValue.
596  * @value: a #gboolean to set within the type.
597  * 
598  * Sets the attribute value to the given boolean value. 
599  * 
600  **/
601 void
602 g_file_attribute_value_set_boolean (GFileAttributeValue *attr,
603                                     gboolean             value)
604 {
605   g_return_if_fail (attr != NULL);
606
607   g_file_attribute_value_clear (attr);
608   attr->type = G_FILE_ATTRIBUTE_TYPE_BOOLEAN;
609   attr->u.boolean = !!value;
610 }
611
612 /**
613  * g_file_attribute_value_set_uint32:
614  * @attr: a #GFileAttributeValue.
615  * @value: a #guint32 to set within the type.
616  * 
617  * Sets the attribute value to the given unsigned 32-bit integer.
618  * 
619  **/ 
620 void
621 g_file_attribute_value_set_uint32 (GFileAttributeValue *attr,
622                                    guint32              value)
623 {
624   g_return_if_fail (attr != NULL);
625
626   g_file_attribute_value_clear (attr);
627   attr->type = G_FILE_ATTRIBUTE_TYPE_UINT32;
628   attr->u.uint32 = value;
629 }
630
631 /**
632  * g_file_attribute_value_set_int32:
633  * @attr: a #GFileAttributeValue.
634  * @value: a #gint32 to set within the type.
635  * 
636  * Sets the attribute value to the given signed 32-bit integer.
637  *  
638  **/
639 void
640 g_file_attribute_value_set_int32 (GFileAttributeValue *attr,
641                                   gint32               value)
642 {
643   g_return_if_fail (attr != NULL);
644
645   g_file_attribute_value_clear (attr);
646   attr->type = G_FILE_ATTRIBUTE_TYPE_INT32;
647   attr->u.int32 = value;
648 }
649
650 /**
651  * g_file_attribute_value_set_uint64:
652  * @attr: a #GFileAttributeValue.
653  * @value: a #guint64 to set within the type.
654  * 
655  * Sets the attribute value to a given unsigned 64-bit integer.
656  * 
657  **/
658 void
659 g_file_attribute_value_set_uint64 (GFileAttributeValue *attr,
660                                    guint64              value)
661 {
662   g_return_if_fail (attr != NULL);
663
664   g_file_attribute_value_clear (attr);
665   attr->type = G_FILE_ATTRIBUTE_TYPE_UINT64;
666   attr->u.uint64 = value;
667 }
668
669 /**
670  * g_file_attribute_value_set_int64:
671  * @attr: a #GFileAttributeValue.
672  * @value: a #gint64 to set within the type.
673  * 
674  * Sets the attribute value to a given signed 64-bit integer. 
675  * 
676  **/
677 void
678 g_file_attribute_value_set_int64 (GFileAttributeValue *attr,
679                                   gint64               value)
680 {
681   g_return_if_fail (attr != NULL);
682
683   g_file_attribute_value_clear (attr);
684   attr->type = G_FILE_ATTRIBUTE_TYPE_INT64;
685   attr->u.int64 = value;
686 }
687
688 /**
689  * g_file_attribute_value_set_object:
690  * @attr: a #GFileAttributeValue.
691  * @obj: a #GObject.
692  *
693  * Sets the attribute to contain the value @obj.
694  * The @attr references the GObject internally.
695  * 
696  **/
697 void
698 g_file_attribute_value_set_object (GFileAttributeValue *attr,
699                                    GObject             *obj)
700 {
701   g_return_if_fail (attr != NULL);
702   g_return_if_fail (obj != NULL);
703
704   g_file_attribute_value_clear (attr);
705   attr->type = G_FILE_ATTRIBUTE_TYPE_OBJECT;
706   attr->u.obj = g_object_ref (obj);
707 }
708
709 typedef struct {
710   GFileAttributeInfoList public;
711   GArray *array;
712   int ref_count;
713 } GFileAttributeInfoListPriv;
714
715 static void
716 list_update_public (GFileAttributeInfoListPriv *priv)
717 {
718   priv->public.infos = (GFileAttributeInfo *)priv->array->data;
719   priv->public.n_infos = priv->array->len;
720 }
721
722 /**
723  * g_file_attribute_info_list_new:
724  * 
725  * Creates a new file attribute info list.
726  * 
727  * Returns: a #GFileAttributeInfoList.
728  **/
729 GFileAttributeInfoList *
730 g_file_attribute_info_list_new (void)
731 {
732   GFileAttributeInfoListPriv *priv;
733
734   priv = g_new0 (GFileAttributeInfoListPriv, 1);
735   
736   priv->ref_count = 1;
737   priv->array = g_array_new (TRUE, FALSE, sizeof (GFileAttributeInfo));
738   
739   list_update_public (priv);
740   
741   return (GFileAttributeInfoList *)priv;
742 }
743
744 /**
745  * g_file_attribute_info_list_dup:
746  * @list: a #GFileAttributeInfoList to duplicate.
747  * 
748  * Makes a duplicate of a file attribute info list.
749  * 
750  * Returns a duplicate of the given @list. 
751  **/
752 GFileAttributeInfoList *
753 g_file_attribute_info_list_dup (GFileAttributeInfoList *list)
754 {
755   GFileAttributeInfoListPriv *new;
756   int i;
757   
758   g_return_val_if_fail (list != NULL, NULL);
759
760   new = g_new0 (GFileAttributeInfoListPriv, 1);
761   new->ref_count = 1;
762   new->array = g_array_new (TRUE, FALSE, sizeof (GFileAttributeInfo));
763
764   g_array_set_size (new->array, list->n_infos);
765   list_update_public (new);
766   for (i = 0; i < list->n_infos; i++)
767     {
768       new->public.infos[i].name = g_strdup (list->infos[i].name);
769       new->public.infos[i].type = list->infos[i].type;
770       new->public.infos[i].flags = list->infos[i].flags;
771     }
772   
773   return (GFileAttributeInfoList *)new;
774 }
775
776 /**
777  * g_file_attribute_info_list_ref:
778  * @list: a #GFileAttributeInfoList to reference.
779  * 
780  * References a file attribute info list.
781  * 
782  * Returns: #GFileAttributeInfoList or %NULL on error.
783  **/
784 GFileAttributeInfoList *
785 g_file_attribute_info_list_ref (GFileAttributeInfoList *list)
786 {
787   GFileAttributeInfoListPriv *priv = (GFileAttributeInfoListPriv *)list;
788   
789   g_return_val_if_fail (list != NULL, NULL);
790   g_return_val_if_fail (priv->ref_count > 0, NULL);
791   
792   g_atomic_int_inc (&priv->ref_count);
793   
794   return list;
795 }
796
797 /**
798  * g_file_attribute_info_list_unref:
799  * @list: The #GFileAttributeInfoList to unreference.
800  * 
801  * Removes a reference from the given @list. If the reference count
802  * falls to zero, the @list is deleted.
803  **/
804 void
805 g_file_attribute_info_list_unref (GFileAttributeInfoList *list)
806 {
807   GFileAttributeInfoListPriv *priv = (GFileAttributeInfoListPriv *)list;
808   int i;
809   
810   g_return_if_fail (list != NULL);
811   g_return_if_fail (priv->ref_count > 0);
812   
813   if (g_atomic_int_dec_and_test (&priv->ref_count))
814     {
815       for (i = 0; i < list->n_infos; i++)
816         g_free (list->infos[i].name);
817       g_array_free (priv->array, TRUE);
818     }
819 }
820
821 static int
822 g_file_attribute_info_list_bsearch (GFileAttributeInfoList *list,
823                                     const char             *name)
824 {
825   int start, end, mid;
826   
827   start = 0;
828   end = list->n_infos;
829
830   while (start != end)
831     {
832       mid = start + (end - start) / 2;
833
834       if (strcmp (name, list->infos[mid].name) < 0)
835         end = mid;
836       else if (strcmp (name, list->infos[mid].name) > 0)
837         start = mid + 1;
838       else
839         return mid;
840     }
841   return start;
842 }
843
844 /**
845  * g_file_attribute_info_list_lookup:
846  * @list: a #GFileAttributeInfoList.
847  * @name: the name of the attribute to lookup.
848  * 
849  * Returns: a #GFileAttributeInfo for the @name, or %NULL if an 
850  * attribute isn't found.
851  **/
852 const GFileAttributeInfo *
853 g_file_attribute_info_list_lookup (GFileAttributeInfoList *list,
854                                    const char             *name)
855 {
856   int i;
857   
858   g_return_val_if_fail (list != NULL, NULL);
859   g_return_val_if_fail (name != NULL, NULL);
860   
861   i = g_file_attribute_info_list_bsearch (list, name);
862
863   if (i < list->n_infos && strcmp (list->infos[i].name, name) == 0)
864     return &list->infos[i];
865   
866   return NULL;
867 }
868
869 /**
870  * g_file_attribute_info_list_add:
871  * @list: a #GFileAttributeInfoList.
872  * @name: the name of the attribute to add.
873  * @type: the #GFileAttributeType for the attribute.
874  * @flags: #GFileAttributeFlags for the attribute.
875  * 
876  * Adds a new attribute with @name to the @list, setting
877  * its @type and @flags. 
878  * 
879  **/
880 void
881 g_file_attribute_info_list_add    (GFileAttributeInfoList *list,
882                                    const char             *name,
883                                    GFileAttributeType      type,
884                                    GFileAttributeFlags     flags)
885 {
886   GFileAttributeInfoListPriv *priv = (GFileAttributeInfoListPriv *)list;
887   GFileAttributeInfo info;
888   int i;
889   
890   g_return_if_fail (list != NULL);
891   g_return_if_fail (name != NULL);
892
893   i = g_file_attribute_info_list_bsearch (list, name);
894
895   if (i < list->n_infos && strcmp (list->infos[i].name, name) == 0)
896     {
897       list->infos[i].type = type;
898       return;
899     }
900
901   info.name = g_strdup (name);
902   info.type = type;
903   info.flags = flags;
904   g_array_insert_vals (priv->array, i, &info, 1);
905
906   list_update_public (priv);
907 }