Home | History | Annotate | Download | only in gio
      1 /* GIO - GLib Input, Output and Streaming Library
      2  *
      3  * Copyright (C) 2006-2007 Red Hat, Inc.
      4  *
      5  * This library is free software; you can redistribute it and/or
      6  * modify it under the terms of the GNU Lesser General Public
      7  * License as published by the Free Software Foundation; either
      8  * version 2 of the License, or (at your option) any later version.
      9  *
     10  * This library is distributed in the hope that it will be useful,
     11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13  * Lesser General Public License for more details.
     14  *
     15  * You should have received a copy of the GNU Lesser General
     16  * Public License along with this library; if not, write to the
     17  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
     18  * Boston, MA 02111-1307, USA.
     19  *
     20  * Author: Alexander Larsson <alexl (at) redhat.com>
     21  *         David Zeuthen <davidz (at) redhat.com>
     22  */
     23 
     24 #include "config.h"
     25 #include "gmount.h"
     26 #include "gvolume.h"
     27 #include "gasyncresult.h"
     28 #include "gsimpleasyncresult.h"
     29 #include "gioerror.h"
     30 #include "glibintl.h"
     31 
     32 #include "gioalias.h"
     33 
     34 /**
     35  * SECTION:gvolume
     36  * @short_description: Volume management
     37  * @include: gio/gio.h
     38  *
     39  * The #GVolume interface represents user-visible objects that can be
     40  * mounted. Note, when porting from GnomeVFS, #GVolume is the moral
     41  * equivalent of #GnomeVFSDrive.
     42  *
     43  * Mounting a #GVolume instance is an asynchronous operation. For more
     44  * information about asynchronous operations, see #GAsyncReady and
     45  * #GSimpleAsyncReady. To mount a #GVolume, first call
     46  * g_volume_mount() with (at least) the #GVolume instance, optionally
     47  * a #GMountOperation object and a #GAsyncReadyCallback.
     48  *
     49  * Typically, one will only want to pass %NULL for the
     50  * #GMountOperation if automounting all volumes when a desktop session
     51  * starts since it's not desirable to put up a lot of dialogs asking
     52  * for credentials.
     53  *
     54  * The callback will be fired when the operation has resolved (either
     55  * with success or failure), and a #GAsyncReady structure will be
     56  * passed to the callback.  That callback should then call
     57  * g_volume_mount_finish() with the #GVolume instance and the
     58  * #GAsyncReady data to see if the operation was completed
     59  * successfully.  If an @error is present when g_volume_mount_finish()
     60  * is called, then it will be filled with any error information.
     61  *
     62  * <para id="volume-identifier">
     63  * It is sometimes necessary to directly access the underlying
     64  * operating system object behind a volume (e.g. for passing a volume
     65  * to an application via the commandline). For this purpose, GIO
     66  * allows to obtain an 'identifier' for the volume. There can be
     67  * different kinds of identifiers, such as Hal UDIs, filesystem labels,
     68  * traditional Unix devices (e.g. <filename>/dev/sda2</filename>),
     69  * uuids. GIO uses predefind strings as names for the different kinds
     70  * of identifiers: #G_VOLUME_IDENTIFIER_KIND_HAL_UDI,
     71  * #G_VOLUME_IDENTIFIER_KIND_LABEL, etc. Use g_volume_get_identifier()
     72  * to obtain an identifier for a volume.
     73  * </para>
     74  *
     75  * Note that #G_VOLUME_IDENTIFIER_KIND_HAL_UDI will only be available
     76  * when the gvfs hal volume monitor is in use. Other volume monitors
     77  * will generally be able to provide the #G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE
     78  * identifier, which can be used to obtain a hal device by means of
     79  * libhal_manger_find_device_string_match().
     80  */
     81 
     82 static void g_volume_base_init (gpointer g_class);
     83 static void g_volume_class_init (gpointer g_class,
     84                                  gpointer class_data);
     85 
     86 GType
     87 g_volume_get_type (void)
     88 {
     89   static volatile gsize g_define_type_id__volatile = 0;
     90 
     91   if (g_once_init_enter (&g_define_type_id__volatile))
     92     {
     93       const GTypeInfo volume_info =
     94       {
     95         sizeof (GVolumeIface), /* class_size */
     96 	g_volume_base_init,   /* base_init */
     97 	NULL,		/* base_finalize */
     98 	g_volume_class_init,
     99 	NULL,		/* class_finalize */
    100 	NULL,		/* class_data */
    101 	0,
    102 	0,              /* n_preallocs */
    103 	NULL
    104       };
    105       GType g_define_type_id =
    106 	g_type_register_static (G_TYPE_INTERFACE, I_("GVolume"),
    107 				&volume_info, 0);
    108 
    109       g_type_interface_add_prerequisite (g_define_type_id, G_TYPE_OBJECT);
    110 
    111       g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
    112     }
    113 
    114   return g_define_type_id__volatile;
    115 }
    116 
    117 static void
    118 g_volume_class_init (gpointer g_class,
    119                      gpointer class_data)
    120 {
    121 }
    122 
    123 static void
    124 g_volume_base_init (gpointer g_class)
    125 {
    126   static gboolean initialized = FALSE;
    127 
    128   if (! initialized)
    129     {
    130      /**
    131       * GVolume::changed:
    132       *
    133       * Emitted when the volume has been changed.
    134       **/
    135       g_signal_new (I_("changed"),
    136                     G_TYPE_VOLUME,
    137                     G_SIGNAL_RUN_LAST,
    138                     G_STRUCT_OFFSET (GVolumeIface, changed),
    139                     NULL, NULL,
    140                     g_cclosure_marshal_VOID__VOID,
    141                     G_TYPE_NONE, 0);
    142 
    143      /**
    144       * GVolume::removed:
    145       *
    146       * This signal is emitted when the #GVolume have been removed. If
    147       * the recipient is holding references to the object they should
    148       * release them so the object can be finalized.
    149       **/
    150       g_signal_new (I_("removed"),
    151                     G_TYPE_VOLUME,
    152                     G_SIGNAL_RUN_LAST,
    153                     G_STRUCT_OFFSET (GVolumeIface, removed),
    154                     NULL, NULL,
    155                     g_cclosure_marshal_VOID__VOID,
    156                     G_TYPE_NONE, 0);
    157 
    158       initialized = TRUE;
    159     }
    160 }
    161 
    162 /**
    163  * g_volume_get_name:
    164  * @volume: a #GVolume.
    165  *
    166  * Gets the name of @volume.
    167  *
    168  * Returns: the name for the given @volume. The returned string should
    169  * be freed with g_free() when no longer needed.
    170  **/
    171 char *
    172 g_volume_get_name (GVolume *volume)
    173 {
    174   GVolumeIface *iface;
    175 
    176   g_return_val_if_fail (G_IS_VOLUME (volume), NULL);
    177 
    178   iface = G_VOLUME_GET_IFACE (volume);
    179 
    180   return (* iface->get_name) (volume);
    181 }
    182 
    183 /**
    184  * g_volume_get_icon:
    185  * @volume: a #GVolume.
    186  *
    187  * Gets the icon for @volume.
    188  *
    189  * Returns: a #GIcon.
    190  *     The returned object should be unreffed with g_object_unref()
    191  *     when no longer needed.
    192  **/
    193 GIcon *
    194 g_volume_get_icon (GVolume *volume)
    195 {
    196   GVolumeIface *iface;
    197 
    198   g_return_val_if_fail (G_IS_VOLUME (volume), NULL);
    199 
    200   iface = G_VOLUME_GET_IFACE (volume);
    201 
    202   return (* iface->get_icon) (volume);
    203 }
    204 
    205 /**
    206  * g_volume_get_uuid:
    207  * @volume: a #GVolume.
    208  *
    209  * Gets the UUID for the @volume. The reference is typically based on
    210  * the file system UUID for the volume in question and should be
    211  * considered an opaque string. Returns %NULL if there is no UUID
    212  * available.
    213  *
    214  * Returns: the UUID for @volume or %NULL if no UUID can be computed.
    215  *     The returned string should be freed with g_free()
    216  *     when no longer needed.
    217  **/
    218 char *
    219 g_volume_get_uuid (GVolume *volume)
    220 {
    221   GVolumeIface *iface;
    222 
    223   g_return_val_if_fail (G_IS_VOLUME (volume), NULL);
    224 
    225   iface = G_VOLUME_GET_IFACE (volume);
    226 
    227   return (* iface->get_uuid) (volume);
    228 }
    229 
    230 /**
    231  * g_volume_get_drive:
    232  * @volume: a #GVolume.
    233  *
    234  * Gets the drive for the @volume.
    235  *
    236  * Returns: a #GDrive or %NULL if @volume is not associated with a drive.
    237  *     The returned object should be unreffed with g_object_unref()
    238  *     when no longer needed.
    239  **/
    240 GDrive *
    241 g_volume_get_drive (GVolume *volume)
    242 {
    243   GVolumeIface *iface;
    244 
    245   g_return_val_if_fail (G_IS_VOLUME (volume), NULL);
    246 
    247   iface = G_VOLUME_GET_IFACE (volume);
    248 
    249   return (* iface->get_drive) (volume);
    250 }
    251 
    252 /**
    253  * g_volume_get_mount:
    254  * @volume: a #GVolume.
    255  *
    256  * Gets the mount for the @volume.
    257  *
    258  * Returns: a #GMount or %NULL if @volume isn't mounted.
    259  *     The returned object should be unreffed with g_object_unref()
    260  *     when no longer needed.
    261  **/
    262 GMount *
    263 g_volume_get_mount (GVolume *volume)
    264 {
    265   GVolumeIface *iface;
    266 
    267   g_return_val_if_fail (G_IS_VOLUME (volume), NULL);
    268 
    269   iface = G_VOLUME_GET_IFACE (volume);
    270 
    271   return (* iface->get_mount) (volume);
    272 }
    273 
    274 
    275 /**
    276  * g_volume_can_mount:
    277  * @volume: a #GVolume.
    278  *
    279  * Checks if a volume can be mounted.
    280  *
    281  * Returns: %TRUE if the @volume can be mounted. %FALSE otherwise.
    282  **/
    283 gboolean
    284 g_volume_can_mount (GVolume *volume)
    285 {
    286   GVolumeIface *iface;
    287 
    288   g_return_val_if_fail (G_IS_VOLUME (volume), FALSE);
    289 
    290   iface = G_VOLUME_GET_IFACE (volume);
    291 
    292   if (iface->can_mount == NULL)
    293     return FALSE;
    294 
    295   return (* iface->can_mount) (volume);
    296 }
    297 
    298 /**
    299  * g_volume_can_eject:
    300  * @volume: a #GVolume.
    301  *
    302  * Checks if a volume can be ejected.
    303  *
    304  * Returns: %TRUE if the @volume can be ejected. %FALSE otherwise.
    305  **/
    306 gboolean
    307 g_volume_can_eject (GVolume *volume)
    308 {
    309   GVolumeIface *iface;
    310 
    311   g_return_val_if_fail (G_IS_VOLUME (volume), FALSE);
    312 
    313   iface = G_VOLUME_GET_IFACE (volume);
    314 
    315   if (iface->can_eject == NULL)
    316     return FALSE;
    317 
    318   return (* iface->can_eject) (volume);
    319 }
    320 
    321 /**
    322  * g_volume_should_automount:
    323  * @volume: a #GVolume
    324  *
    325  * Returns whether the volume should be automatically mounted.
    326  *
    327  * Returns: %TRUE if the volume should be automatically mounted.
    328  */
    329 gboolean
    330 g_volume_should_automount (GVolume *volume)
    331 {
    332   GVolumeIface *iface;
    333 
    334   g_return_val_if_fail (G_IS_VOLUME (volume), FALSE);
    335 
    336   iface = G_VOLUME_GET_IFACE (volume);
    337 
    338   if (iface->should_automount == NULL)
    339     return FALSE;
    340 
    341   return (* iface->should_automount) (volume);
    342 }
    343 
    344 
    345 /**
    346  * g_volume_mount:
    347  * @volume: a #GVolume.
    348  * @flags: flags affecting the operation
    349  * @mount_operation: a #GMountOperation or %NULL to avoid user interaction.
    350  * @cancellable: optional #GCancellable object, %NULL to ignore.
    351  * @callback: a #GAsyncReadyCallback, or %NULL.
    352  * @user_data: user data that gets passed to @callback
    353  *
    354  * Mounts a volume. This is an asynchronous operation, and is
    355  * finished by calling g_volume_mount_finish() with the @volume
    356  * and #GAsyncResult returned in the @callback.
    357  **/
    358 void
    359 g_volume_mount (GVolume             *volume,
    360 		GMountMountFlags     flags,
    361                 GMountOperation     *mount_operation,
    362                 GCancellable        *cancellable,
    363                 GAsyncReadyCallback  callback,
    364                 gpointer             user_data)
    365 {
    366   GVolumeIface *iface;
    367 
    368   g_return_if_fail (G_IS_VOLUME (volume));
    369 
    370   iface = G_VOLUME_GET_IFACE (volume);
    371 
    372   if (iface->mount_fn == NULL)
    373     {
    374       g_simple_async_report_error_in_idle (G_OBJECT (volume), callback, user_data,
    375 					   G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
    376 					   _("volume doesn't implement mount"));
    377 
    378       return;
    379     }
    380 
    381   (* iface->mount_fn) (volume, flags, mount_operation, cancellable, callback, user_data);
    382 }
    383 
    384 /**
    385  * g_volume_mount_finish:
    386  * @volume: a #GVolume
    387  * @result: a #GAsyncResult
    388  * @error: a #GError location to store an error, or %NULL to ignore
    389  *
    390  * Finishes mounting a volume. If any errors occured during the operation,
    391  * @error will be set to contain the errors and %FALSE will be returned.
    392  *
    393  * If the mount operation succeeded, g_volume_get_mount() on @volume
    394  * is guaranteed to return the mount right after calling this
    395  * function; there's no need to listen for the 'mount-added' signal on
    396  * #GVolumeMonitor.
    397  *
    398  * Returns: %TRUE, %FALSE if operation failed.
    399  **/
    400 gboolean
    401 g_volume_mount_finish (GVolume       *volume,
    402                        GAsyncResult  *result,
    403                        GError       **error)
    404 {
    405   GVolumeIface *iface;
    406 
    407   g_return_val_if_fail (G_IS_VOLUME (volume), FALSE);
    408   g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
    409 
    410   if (G_IS_SIMPLE_ASYNC_RESULT (result))
    411     {
    412       GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
    413       if (g_simple_async_result_propagate_error (simple, error))
    414 	return FALSE;
    415     }
    416 
    417   iface = G_VOLUME_GET_IFACE (volume);
    418   return (* iface->mount_finish) (volume, result, error);
    419 }
    420 
    421 /**
    422  * g_volume_eject:
    423  * @volume: a #GVolume.
    424  * @flags: flags affecting the unmount if required for eject
    425  * @cancellable: optional #GCancellable object, %NULL to ignore.
    426  * @callback: a #GAsyncReadyCallback, or %NULL.
    427  * @user_data: user data that gets passed to @callback
    428  *
    429  * Ejects a volume. This is an asynchronous operation, and is
    430  * finished by calling g_volume_eject_finish() with the @volume
    431  * and #GAsyncResult returned in the @callback.
    432  **/
    433 void
    434 g_volume_eject (GVolume             *volume,
    435 		GMountUnmountFlags   flags,
    436                 GCancellable        *cancellable,
    437                 GAsyncReadyCallback  callback,
    438                 gpointer             user_data)
    439 {
    440   GVolumeIface *iface;
    441 
    442   g_return_if_fail (G_IS_VOLUME (volume));
    443 
    444   iface = G_VOLUME_GET_IFACE (volume);
    445 
    446   if (iface->eject == NULL)
    447     {
    448       g_simple_async_report_error_in_idle (G_OBJECT (volume), callback, user_data,
    449 					   G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
    450 					   _("volume doesn't implement eject"));
    451 
    452       return;
    453     }
    454 
    455   (* iface->eject) (volume, flags, cancellable, callback, user_data);
    456 }
    457 
    458 /**
    459  * g_volume_eject_finish:
    460  * @volume: pointer to a #GVolume.
    461  * @result: a #GAsyncResult.
    462  * @error: a #GError location to store an error, or %NULL to ignore
    463  *
    464  * Finishes ejecting a volume. If any errors occured during the operation,
    465  * @error will be set to contain the errors and %FALSE will be returned.
    466  *
    467  * Returns: %TRUE, %FALSE if operation failed.
    468  **/
    469 gboolean
    470 g_volume_eject_finish (GVolume       *volume,
    471                        GAsyncResult  *result,
    472                        GError       **error)
    473 {
    474   GVolumeIface *iface;
    475 
    476   g_return_val_if_fail (G_IS_VOLUME (volume), FALSE);
    477   g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
    478 
    479   if (G_IS_SIMPLE_ASYNC_RESULT (result))
    480     {
    481       GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
    482       if (g_simple_async_result_propagate_error (simple, error))
    483 	return FALSE;
    484     }
    485 
    486   iface = G_VOLUME_GET_IFACE (volume);
    487   return (* iface->eject_finish) (volume, result, error);
    488 }
    489 
    490 /**
    491  * g_volume_get_identifier:
    492  * @volume: a #GVolume
    493  * @kind: the kind of identifier to return
    494  *
    495  * Gets the identifier of the given kind for @volume.
    496  * See the <link linkend="volume-identifier">introduction</link>
    497  * for more information about volume identifiers.
    498  *
    499  * Returns: a newly allocated string containing the
    500  *   requested identfier, or %NULL if the #GVolume
    501  *   doesn't have this kind of identifier
    502  */
    503 char *
    504 g_volume_get_identifier (GVolume    *volume,
    505 			 const char *kind)
    506 {
    507   GVolumeIface *iface;
    508 
    509   g_return_val_if_fail (G_IS_VOLUME (volume), NULL);
    510   g_return_val_if_fail (kind != NULL, NULL);
    511 
    512   iface = G_VOLUME_GET_IFACE (volume);
    513 
    514   if (iface->get_identifier == NULL)
    515     return NULL;
    516 
    517   return (* iface->get_identifier) (volume, kind);
    518 }
    519 
    520 /**
    521  * g_volume_enumerate_identifiers:
    522  * @volume: a #GVolume
    523  *
    524  * Gets the kinds of <link linkend="volume-identifier">identifiers</link>
    525  * that @volume has. Use g_volume_get_identifer() to obtain
    526  * the identifiers themselves.
    527  *
    528  * Returns: a %NULL-terminated array of strings containing
    529  *   kinds of identifiers. Use g_strfreev() to free.
    530  */
    531 char **
    532 g_volume_enumerate_identifiers (GVolume *volume)
    533 {
    534   GVolumeIface *iface;
    535 
    536   g_return_val_if_fail (G_IS_VOLUME (volume), NULL);
    537   iface = G_VOLUME_GET_IFACE (volume);
    538 
    539   if (iface->enumerate_identifiers == NULL)
    540     return NULL;
    541 
    542   return (* iface->enumerate_identifiers) (volume);
    543 }
    544 
    545 /**
    546  * g_volume_get_activation_root:
    547  * @volume: a #GVolume
    548  *
    549  * Gets the activation root for a #GVolume if it is known ahead of
    550  * mount time. Returns %NULL otherwise. If not %NULL and if @volume
    551  * is mounted, then the result of g_mount_get_root() on the
    552  * #GMount object obtained from g_volume_get_mount() will always
    553  * either be equal or a prefix of what this function returns. In
    554  * other words, in code
    555  *
    556  * <programlisting>
    557  *   GMount *mount;
    558  *   GFile *mount_root
    559  *   GFile *volume_activation_root;
    560  *
    561  *   mount = g_volume_get_mount (volume); /&ast; mounted, so never NULL &ast;/
    562  *   mount_root = g_mount_get_root (mount);
    563  *   volume_activation_root = g_volume_get_activation_root(volume); /&ast; assume not NULL &ast;/
    564  * </programlisting>
    565  *
    566  * then the expression
    567  *
    568  * <programlisting>
    569  *   (g_file_has_prefix (volume_activation_root, mount_root) ||
    570       g_file_equal (volume_activation_root, mount_root))
    571  * </programlisting>
    572  *
    573  * will always be %TRUE.
    574  *
    575  * Activation roots are typically used in #GVolumeMonitor
    576  * implementations to find the underlying mount to shadow, see
    577  * g_mount_is_shadowed() for more details.
    578  *
    579  * Returns: the activation root of @volume or %NULL. Use
    580  * g_object_unref() to free.
    581  *
    582  * Since: 2.18
    583  **/
    584 GFile *
    585 g_volume_get_activation_root (GVolume *volume)
    586 {
    587   GVolumeIface *iface;
    588 
    589   g_return_val_if_fail (G_IS_VOLUME (volume), NULL);
    590   iface = G_VOLUME_GET_IFACE (volume);
    591 
    592   if (iface->get_activation_root == NULL)
    593     return NULL;
    594 
    595   return (* iface->get_activation_root) (volume);
    596 }
    597 
    598 
    599 
    600 #define __G_VOLUME_C__
    601 #include "gioaliasdef.c"
    602