glib/gio/gvolume.c
Philip Withnall b4332b0056
docs: Clarify distinction between GDrive, GVolume and GMount
Provide examples of what they all represent, and expand on the
descriptions of them in a few places.

Move references to their equivalents from `GnomeVFS` to lower down in
the documentation, since `GnomeVFS` has been deprecated for many years
now, and is unlikely to be pertinent to most readers.

Signed-off-by: Philip Withnall <pwithnall@gnome.org>
2024-08-15 11:32:37 +01:00

692 lines
20 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* GIO - GLib Input, Output and Streaming Library
*
* Copyright (C) 2006-2007 Red Hat, Inc.
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
* Author: Alexander Larsson <alexl@redhat.com>
* David Zeuthen <davidz@redhat.com>
*/
#include "config.h"
#include "gmount.h"
#include "gvolume.h"
#include "gthemedicon.h"
#include "gasyncresult.h"
#include "gtask.h"
#include "gioerror.h"
#include "glibintl.h"
/**
* GVolume:
*
* The `GVolume` interface represents user-visible objects that can be
* mounted. For example, a file system partition on a USB flash drive, or an
* optical disc inserted into a disc drive.
*
* If a `GVolume` is currently mounted, the corresponding [iface@Gio.Mount] can
* be retrieved using [method@Gio.Volume.get_mount].
*
* Mounting a `GVolume` instance is an asynchronous operation. For more
* information about asynchronous operations, see [iface@Gio.AsyncResult] and
* [class@Gio.Task]. To mount a `GVolume`, first call [method@Gio.Volume.mount]
* with (at least) the `GVolume` instance, optionally a
* [class@Gio.MountOperation] object and a [type@Gio.AsyncReadyCallback].
*
* Typically, one will only want to pass `NULL` for the
* [class@Gio.MountOperation] if automounting all volumes when a desktop session
* starts since its not desirable to put up a lot of dialogs asking
* for credentials.
*
* The callback will be fired when the operation has resolved (either
* with success or failure), and a [iface@Gio.AsyncResult] instance will be
* passed to the callback. That callback should then call
* [method@Gio.Volume.mount_finish] with the `GVolume` instance and the
* [iface@Gio.AsyncResult] data to see if the operation was completed
* successfully. If a [type@GLib.Error] is present when
* [method@Gio.Volume.mount_finish] is called, then it will be filled with any
* error information.
*
* Note, when [porting from GnomeVFS](migrating-gnome-vfs.html),
* `GVolume` is the moral equivalent of `GnomeVFSDrive`.
*
* ## Volume Identifiers
*
* It is sometimes necessary to directly access the underlying
* operating system object behind a volume (e.g. for passing a volume
* to an application via the command line). For this purpose, GIO
* allows to obtain an identifier for the volume. There can be
* different kinds of identifiers, such as Hal UDIs, filesystem labels,
* traditional Unix devices (e.g. `/dev/sda2`), UUIDs. GIO uses predefined
* strings as names for the different kinds of identifiers:
* `G_VOLUME_IDENTIFIER_KIND_UUID`, `G_VOLUME_IDENTIFIER_KIND_LABEL`, etc.
* Use [method@Gio.Volume.get_identifier] to obtain an identifier for a volume.
*
* Note that `G_VOLUME_IDENTIFIER_KIND_HAL_UDI` will only be available
* when the GVFS hal volume monitor is in use. Other volume monitors
* will generally be able to provide the `G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE`
* identifier, which can be used to obtain a hal device by means of
* `libhal_manager_find_device_string_match()`.
*/
typedef GVolumeIface GVolumeInterface;
G_DEFINE_INTERFACE(GVolume, g_volume, G_TYPE_OBJECT)
static void
g_volume_default_init (GVolumeInterface *iface)
{
/**
* GVolume::changed:
*
* Emitted when the volume has been changed.
*/
g_signal_new (I_("changed"),
G_TYPE_VOLUME,
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GVolumeIface, changed),
NULL, NULL,
NULL,
G_TYPE_NONE, 0);
/**
* GVolume::removed:
*
* This signal is emitted when the #GVolume have been removed. If
* the recipient is holding references to the object they should
* release them so the object can be finalized.
*/
g_signal_new (I_("removed"),
G_TYPE_VOLUME,
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GVolumeIface, removed),
NULL, NULL,
NULL,
G_TYPE_NONE, 0);
}
/**
* g_volume_get_name:
* @volume: a #GVolume
*
* Gets the name of @volume.
*
* Returns: the name for the given @volume. The returned string should
* be freed with g_free() when no longer needed.
*/
char *
g_volume_get_name (GVolume *volume)
{
GVolumeIface *iface;
g_return_val_if_fail (G_IS_VOLUME (volume), NULL);
iface = G_VOLUME_GET_IFACE (volume);
return (* iface->get_name) (volume);
}
/**
* g_volume_get_icon:
* @volume: a #GVolume
*
* Gets the icon for @volume.
*
* Returns: (transfer full): a #GIcon.
* The returned object should be unreffed with g_object_unref()
* when no longer needed.
*/
GIcon *
g_volume_get_icon (GVolume *volume)
{
GVolumeIface *iface;
g_return_val_if_fail (G_IS_VOLUME (volume), NULL);
iface = G_VOLUME_GET_IFACE (volume);
return (* iface->get_icon) (volume);
}
/**
* g_volume_get_symbolic_icon:
* @volume: a #GVolume
*
* Gets the symbolic icon for @volume.
*
* Returns: (transfer full): a #GIcon.
* The returned object should be unreffed with g_object_unref()
* when no longer needed.
*
* Since: 2.34
*/
GIcon *
g_volume_get_symbolic_icon (GVolume *volume)
{
GVolumeIface *iface;
GIcon *ret;
g_return_val_if_fail (G_IS_VOLUME (volume), NULL);
iface = G_VOLUME_GET_IFACE (volume);
if (iface->get_symbolic_icon != NULL)
ret = iface->get_symbolic_icon (volume);
else
ret = g_themed_icon_new_with_default_fallbacks ("folder-remote-symbolic");
return ret;
}
/**
* g_volume_get_uuid:
* @volume: a #GVolume
*
* Gets the UUID for the @volume. The reference is typically based on
* the file system UUID for the volume in question and should be
* considered an opaque string. Returns %NULL if there is no UUID
* available.
*
* Returns: (nullable) (transfer full): the UUID for @volume or %NULL if no UUID
* can be computed.
* The returned string should be freed with g_free()
* when no longer needed.
*/
char *
g_volume_get_uuid (GVolume *volume)
{
GVolumeIface *iface;
g_return_val_if_fail (G_IS_VOLUME (volume), NULL);
iface = G_VOLUME_GET_IFACE (volume);
return (* iface->get_uuid) (volume);
}
/**
* g_volume_get_drive:
* @volume: a #GVolume
*
* Gets the drive for the @volume.
*
* Returns: (transfer full) (nullable): a #GDrive or %NULL if @volume is not
* associated with a drive. The returned object should be unreffed
* with g_object_unref() when no longer needed.
*/
GDrive *
g_volume_get_drive (GVolume *volume)
{
GVolumeIface *iface;
g_return_val_if_fail (G_IS_VOLUME (volume), NULL);
iface = G_VOLUME_GET_IFACE (volume);
return (* iface->get_drive) (volume);
}
/**
* g_volume_get_mount:
* @volume: a #GVolume
*
* Gets the mount for the @volume.
*
* Returns: (transfer full) (nullable): a #GMount or %NULL if @volume isn't mounted.
* The returned object should be unreffed with g_object_unref()
* when no longer needed.
*/
GMount *
g_volume_get_mount (GVolume *volume)
{
GVolumeIface *iface;
g_return_val_if_fail (G_IS_VOLUME (volume), NULL);
iface = G_VOLUME_GET_IFACE (volume);
return (* iface->get_mount) (volume);
}
/**
* g_volume_can_mount:
* @volume: a #GVolume
*
* Checks if a volume can be mounted.
*
* Returns: %TRUE if the @volume can be mounted. %FALSE otherwise
*/
gboolean
g_volume_can_mount (GVolume *volume)
{
GVolumeIface *iface;
g_return_val_if_fail (G_IS_VOLUME (volume), FALSE);
iface = G_VOLUME_GET_IFACE (volume);
if (iface->can_mount == NULL)
return FALSE;
return (* iface->can_mount) (volume);
}
/**
* g_volume_can_eject:
* @volume: a #GVolume
*
* Checks if a volume can be ejected.
*
* Returns: %TRUE if the @volume can be ejected. %FALSE otherwise
*/
gboolean
g_volume_can_eject (GVolume *volume)
{
GVolumeIface *iface;
g_return_val_if_fail (G_IS_VOLUME (volume), FALSE);
iface = G_VOLUME_GET_IFACE (volume);
if (iface->can_eject == NULL)
return FALSE;
return (* iface->can_eject) (volume);
}
/**
* g_volume_should_automount:
* @volume: a #GVolume
*
* Returns whether the volume should be automatically mounted.
*
* Returns: %TRUE if the volume should be automatically mounted
*/
gboolean
g_volume_should_automount (GVolume *volume)
{
GVolumeIface *iface;
g_return_val_if_fail (G_IS_VOLUME (volume), FALSE);
iface = G_VOLUME_GET_IFACE (volume);
if (iface->should_automount == NULL)
return FALSE;
return (* iface->should_automount) (volume);
}
/**
* g_volume_mount: (virtual mount_fn)
* @volume: a #GVolume
* @flags: flags affecting the operation
* @mount_operation: (nullable): a #GMountOperation or %NULL to avoid user interaction
* @cancellable: (nullable): optional #GCancellable object, %NULL to ignore
* @callback: (nullable): a #GAsyncReadyCallback, or %NULL
* @user_data: user data that gets passed to @callback
*
* Mounts a volume. This is an asynchronous operation, and is
* finished by calling g_volume_mount_finish() with the @volume
* and #GAsyncResult returned in the @callback.
*/
void
g_volume_mount (GVolume *volume,
GMountMountFlags flags,
GMountOperation *mount_operation,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GVolumeIface *iface;
g_return_if_fail (G_IS_VOLUME (volume));
iface = G_VOLUME_GET_IFACE (volume);
if (iface->mount_fn == NULL)
{
g_task_report_new_error (volume, callback, user_data,
g_volume_mount,
G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
_("volume doesnt implement mount"));
return;
}
(* iface->mount_fn) (volume, flags, mount_operation, cancellable, callback, user_data);
}
/**
* g_volume_mount_finish:
* @volume: a #GVolume
* @result: a #GAsyncResult
* @error: a #GError location to store an error, or %NULL to ignore
*
* Finishes mounting a volume. If any errors occurred during the operation,
* @error will be set to contain the errors and %FALSE will be returned.
*
* If the mount operation succeeded, g_volume_get_mount() on @volume
* is guaranteed to return the mount right after calling this
* function; there's no need to listen for the 'mount-added' signal on
* #GVolumeMonitor.
*
* Returns: %TRUE, %FALSE if operation failed
*/
gboolean
g_volume_mount_finish (GVolume *volume,
GAsyncResult *result,
GError **error)
{
GVolumeIface *iface;
g_return_val_if_fail (G_IS_VOLUME (volume), FALSE);
g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
if (g_async_result_legacy_propagate_error (result, error))
return FALSE;
else if (g_async_result_is_tagged (result, g_volume_mount))
return g_task_propagate_boolean (G_TASK (result), error);
iface = G_VOLUME_GET_IFACE (volume);
return (* iface->mount_finish) (volume, result, error);
}
/**
* g_volume_eject:
* @volume: a #GVolume
* @flags: flags affecting the unmount if required for eject
* @cancellable: (nullable): optional #GCancellable object, %NULL to ignore
* @callback: (nullable): a #GAsyncReadyCallback, or %NULL
* @user_data: user data that gets passed to @callback
*
* Ejects a volume. This is an asynchronous operation, and is
* finished by calling g_volume_eject_finish() with the @volume
* and #GAsyncResult returned in the @callback.
*
* Deprecated: 2.22: Use g_volume_eject_with_operation() instead.
*/
void
g_volume_eject (GVolume *volume,
GMountUnmountFlags flags,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GVolumeIface *iface;
g_return_if_fail (G_IS_VOLUME (volume));
iface = G_VOLUME_GET_IFACE (volume);
if (iface->eject == NULL)
{
g_task_report_new_error (volume, callback, user_data,
g_volume_eject_with_operation,
G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
_("volume doesnt implement eject"));
return;
}
(* iface->eject) (volume, flags, cancellable, callback, user_data);
}
/**
* g_volume_eject_finish:
* @volume: pointer to a #GVolume
* @result: a #GAsyncResult
* @error: a #GError location to store an error, or %NULL to ignore
*
* Finishes ejecting a volume. If any errors occurred during the operation,
* @error will be set to contain the errors and %FALSE will be returned.
*
* Returns: %TRUE, %FALSE if operation failed
*
* Deprecated: 2.22: Use g_volume_eject_with_operation_finish() instead.
**/
gboolean
g_volume_eject_finish (GVolume *volume,
GAsyncResult *result,
GError **error)
{
GVolumeIface *iface;
g_return_val_if_fail (G_IS_VOLUME (volume), FALSE);
g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
if (g_async_result_legacy_propagate_error (result, error))
return FALSE;
if (g_async_result_is_tagged (result, g_volume_eject_with_operation))
return g_task_propagate_boolean (G_TASK (result), error);
iface = G_VOLUME_GET_IFACE (volume);
return (* iface->eject_finish) (volume, result, error);
}
/**
* g_volume_eject_with_operation:
* @volume: a #GVolume
* @flags: flags affecting the unmount if required for eject
* @mount_operation: (nullable): a #GMountOperation or %NULL to
* avoid user interaction
* @cancellable: (nullable): optional #GCancellable object, %NULL to ignore
* @callback: (nullable): a #GAsyncReadyCallback, or %NULL
* @user_data: user data passed to @callback
*
* Ejects a volume. This is an asynchronous operation, and is
* finished by calling g_volume_eject_with_operation_finish() with the @volume
* and #GAsyncResult data returned in the @callback.
*
* Since: 2.22
**/
void
g_volume_eject_with_operation (GVolume *volume,
GMountUnmountFlags flags,
GMountOperation *mount_operation,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GVolumeIface *iface;
g_return_if_fail (G_IS_VOLUME (volume));
iface = G_VOLUME_GET_IFACE (volume);
if (iface->eject == NULL && iface->eject_with_operation == NULL)
{
g_task_report_new_error (volume, callback, user_data,
g_volume_eject_with_operation,
G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
/* Translators: This is an error
* message for volume objects that
* don't implement any of eject or eject_with_operation. */
_("volume doesnt implement eject or eject_with_operation"));
return;
}
if (iface->eject_with_operation != NULL)
(* iface->eject_with_operation) (volume, flags, mount_operation, cancellable, callback, user_data);
else
(* iface->eject) (volume, flags, cancellable, callback, user_data);
}
/**
* g_volume_eject_with_operation_finish:
* @volume: a #GVolume
* @result: a #GAsyncResult
* @error: a #GError location to store the error occurring, or %NULL
*
* Finishes ejecting a volume. If any errors occurred during the operation,
* @error will be set to contain the errors and %FALSE will be returned.
*
* Returns: %TRUE if the volume was successfully ejected. %FALSE otherwise
*
* Since: 2.22
**/
gboolean
g_volume_eject_with_operation_finish (GVolume *volume,
GAsyncResult *result,
GError **error)
{
GVolumeIface *iface;
g_return_val_if_fail (G_IS_VOLUME (volume), FALSE);
g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
if (g_async_result_legacy_propagate_error (result, error))
return FALSE;
else if (g_async_result_is_tagged (result, g_volume_eject_with_operation))
return g_task_propagate_boolean (G_TASK (result), error);
iface = G_VOLUME_GET_IFACE (volume);
if (iface->eject_with_operation_finish != NULL)
return (* iface->eject_with_operation_finish) (volume, result, error);
else
return (* iface->eject_finish) (volume, result, error);
}
/**
* g_volume_get_identifier:
* @volume: a #GVolume
* @kind: the kind of identifier to return
*
* Gets the identifier of the given kind for @volume.
* See the [introduction](#volume-identifiers) for more
* information about volume identifiers.
*
* Returns: (nullable) (transfer full): a newly allocated string containing the
* requested identifier, or %NULL if the #GVolume
* doesn't have this kind of identifier
*/
char *
g_volume_get_identifier (GVolume *volume,
const char *kind)
{
GVolumeIface *iface;
g_return_val_if_fail (G_IS_VOLUME (volume), NULL);
g_return_val_if_fail (kind != NULL, NULL);
iface = G_VOLUME_GET_IFACE (volume);
if (iface->get_identifier == NULL)
return NULL;
return (* iface->get_identifier) (volume, kind);
}
/**
* g_volume_enumerate_identifiers:
* @volume: a #GVolume
*
* Gets the kinds of [identifiers](#volume-identifiers) that @volume has.
* Use g_volume_get_identifier() to obtain the identifiers themselves.
*
* Returns: (array zero-terminated=1) (transfer full): a %NULL-terminated array
* of strings containing kinds of identifiers. Use g_strfreev() to free.
*/
char **
g_volume_enumerate_identifiers (GVolume *volume)
{
GVolumeIface *iface;
g_return_val_if_fail (G_IS_VOLUME (volume), NULL);
iface = G_VOLUME_GET_IFACE (volume);
if (iface->enumerate_identifiers == NULL)
return NULL;
return (* iface->enumerate_identifiers) (volume);
}
/**
* g_volume_get_activation_root:
* @volume: a #GVolume
*
* Gets the activation root for a #GVolume if it is known ahead of
* mount time. Returns %NULL otherwise. If not %NULL and if @volume
* is mounted, then the result of g_mount_get_root() on the
* #GMount object obtained from g_volume_get_mount() will always
* either be equal or a prefix of what this function returns. In
* other words, in code
*
* |[<!-- language="C" -->
* GMount *mount;
* GFile *mount_root
* GFile *volume_activation_root;
*
* mount = g_volume_get_mount (volume); // mounted, so never NULL
* mount_root = g_mount_get_root (mount);
* volume_activation_root = g_volume_get_activation_root (volume); // assume not NULL
* ]|
* then the expression
* |[<!-- language="C" -->
* (g_file_has_prefix (volume_activation_root, mount_root) ||
* g_file_equal (volume_activation_root, mount_root))
* ]|
* will always be %TRUE.
*
* Activation roots are typically used in #GVolumeMonitor
* implementations to find the underlying mount to shadow, see
* g_mount_is_shadowed() for more details.
*
* Returns: (nullable) (transfer full): the activation root of @volume
* or %NULL. Use g_object_unref() to free.
*
* Since: 2.18
*/
GFile *
g_volume_get_activation_root (GVolume *volume)
{
GVolumeIface *iface;
g_return_val_if_fail (G_IS_VOLUME (volume), NULL);
iface = G_VOLUME_GET_IFACE (volume);
if (iface->get_activation_root == NULL)
return NULL;
return (* iface->get_activation_root) (volume);
}
/**
* g_volume_get_sort_key:
* @volume: a #GVolume
*
* Gets the sort key for @volume, if any.
*
* Returns: (nullable): Sorting key for @volume or %NULL if no such key is available
*
* Since: 2.32
*/
const gchar *
g_volume_get_sort_key (GVolume *volume)
{
const gchar *ret = NULL;
GVolumeIface *iface;
g_return_val_if_fail (G_IS_VOLUME (volume), NULL);
iface = G_VOLUME_GET_IFACE (volume);
if (iface->get_sort_key != NULL)
ret = iface->get_sort_key (volume);
return ret;
}