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