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