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