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 "<invalid>" 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