(root)/
glib-2.79.0/
gio/
gdrive.c
       1  /* GIO - GLib Input, Output and Streaming Library
       2   * 
       3   * Copyright (C) 2006-2007 Red Hat, Inc.
       4   *
       5   * SPDX-License-Identifier: LGPL-2.1-or-later
       6   *
       7   * This library is free software; you can redistribute it and/or
       8   * modify it under the terms of the GNU Lesser General Public
       9   * License as published by the Free Software Foundation; either
      10   * version 2.1 of the License, or (at your option) any later version.
      11   *
      12   * This library is distributed in the hope that it will be useful,
      13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
      14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15   * Lesser General Public License for more details.
      16   *
      17   * You should have received a copy of the GNU Lesser General
      18   * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
      19   *
      20   * Author: Alexander Larsson <alexl@redhat.com>
      21   *         David Zeuthen <davidz@redhat.com>
      22   */
      23  
      24  #include "config.h"
      25  #include "gdrive.h"
      26  #include "gtask.h"
      27  #include "gthemedicon.h"
      28  #include "gasyncresult.h"
      29  #include "gioerror.h"
      30  #include "glibintl.h"
      31  
      32  
      33  /**
      34   * GDrive:
      35   *
      36   * `GDrive` represents a piece of hardware connected to the machine.
      37   * It’s generally only created for removable hardware or hardware with
      38   * removable media.
      39   *
      40   * `GDrive` is a container class for [iface@Gio.Volume] objects that stem from
      41   * the same piece of media. As such, `GDrive` abstracts a drive with
      42   * (or without) removable media and provides operations for querying
      43   * whether media is available, determining whether media change is
      44   * automatically detected and ejecting the media.
      45   *
      46   * If the `GDrive` reports that media isn’t automatically detected, one
      47   * can poll for media; typically one should not do this periodically
      48   * as a poll for media operation is potentially expensive and may
      49   * spin up the drive creating noise.
      50   *
      51   * `GDrive` supports starting and stopping drives with authentication
      52   * support for the former. This can be used to support a diverse set
      53   * of use cases including connecting/disconnecting iSCSI devices,
      54   * powering down external disk enclosures and starting/stopping
      55   * multi-disk devices such as RAID devices. Note that the actual
      56   * semantics and side-effects of starting/stopping a `GDrive` may vary
      57   * according to implementation. To choose the correct verbs in e.g. a
      58   * file manager, use [method@Gio.Drive.get_start_stop_type].
      59   *
      60   * For [porting from GnomeVFS](migrating-gnome-vfs.html) note that there is no
      61   * equivalent of `GDrive` in that API.
      62   **/
      63  
      64  typedef GDriveIface GDriveInterface;
      65  G_DEFINE_INTERFACE(GDrive, g_drive, G_TYPE_OBJECT)
      66  
      67  static void
      68  g_drive_default_init (GDriveInterface *iface)
      69  {
      70    /**
      71     * GDrive::changed:
      72     * @drive: a #GDrive.
      73     *
      74     * Emitted when the drive's state has changed.
      75     **/
      76    g_signal_new (I_("changed"),
      77  		G_TYPE_DRIVE,
      78  		G_SIGNAL_RUN_LAST,
      79  		G_STRUCT_OFFSET (GDriveIface, changed),
      80  		NULL, NULL,
      81  		NULL,
      82  		G_TYPE_NONE, 0);
      83  
      84    /**
      85     * GDrive::disconnected:
      86     * @drive: a #GDrive.
      87     *
      88     * This signal is emitted when the #GDrive have been
      89     * disconnected. If the recipient is holding references to the
      90     * object they should release them so the object can be
      91     * finalized.
      92     **/
      93    g_signal_new (I_("disconnected"),
      94  		G_TYPE_DRIVE,
      95  		G_SIGNAL_RUN_LAST,
      96  		G_STRUCT_OFFSET (GDriveIface, disconnected),
      97  		NULL, NULL,
      98  		NULL,
      99  		G_TYPE_NONE, 0);
     100  
     101    /**
     102     * GDrive::eject-button:
     103     * @drive: a #GDrive.
     104     *
     105     * Emitted when the physical eject button (if any) of a drive has
     106     * been pressed.
     107     **/
     108    g_signal_new (I_("eject-button"),
     109  		G_TYPE_DRIVE,
     110  		G_SIGNAL_RUN_LAST,
     111  		G_STRUCT_OFFSET (GDriveIface, eject_button),
     112  		NULL, NULL,
     113  		NULL,
     114  		G_TYPE_NONE, 0);
     115  
     116    /**
     117     * GDrive::stop-button:
     118     * @drive: a #GDrive.
     119     *
     120     * Emitted when the physical stop button (if any) of a drive has
     121     * been pressed.
     122     *
     123     * Since: 2.22
     124     **/
     125    g_signal_new (I_("stop-button"),
     126  		G_TYPE_DRIVE,
     127  		G_SIGNAL_RUN_LAST,
     128  		G_STRUCT_OFFSET (GDriveIface, stop_button),
     129  		NULL, NULL,
     130  		NULL,
     131  		G_TYPE_NONE, 0);
     132  }
     133  
     134  /**
     135   * g_drive_get_name:
     136   * @drive: a #GDrive.
     137   * 
     138   * Gets the name of @drive.
     139   *
     140   * Returns: a string containing @drive's name. The returned 
     141   *     string should be freed when no longer needed.
     142   **/
     143  char *
     144  g_drive_get_name (GDrive *drive)
     145  {
     146    GDriveIface *iface;
     147  
     148    g_return_val_if_fail (G_IS_DRIVE (drive), NULL);
     149  
     150    iface = G_DRIVE_GET_IFACE (drive);
     151  
     152    return (* iface->get_name) (drive);
     153  }
     154  
     155  /**
     156   * g_drive_get_icon:
     157   * @drive: a #GDrive.
     158   * 
     159   * Gets the icon for @drive.
     160   * 
     161   * Returns: (transfer full): #GIcon for the @drive.
     162   *    Free the returned object with g_object_unref().
     163   **/
     164  GIcon *
     165  g_drive_get_icon (GDrive *drive)
     166  {
     167    GDriveIface *iface;
     168    
     169    g_return_val_if_fail (G_IS_DRIVE (drive), NULL);
     170  
     171    iface = G_DRIVE_GET_IFACE (drive);
     172  
     173    return (* iface->get_icon) (drive);
     174  }
     175  
     176  /**
     177   * g_drive_get_symbolic_icon:
     178   * @drive: a #GDrive.
     179   * 
     180   * Gets the icon for @drive.
     181   * 
     182   * Returns: (transfer full): symbolic #GIcon for the @drive.
     183   *    Free the returned object with g_object_unref().
     184   *
     185   * Since: 2.34
     186   **/
     187  GIcon *
     188  g_drive_get_symbolic_icon (GDrive *drive)
     189  {
     190    GDriveIface *iface;
     191    GIcon *ret;
     192  
     193    g_return_val_if_fail (G_IS_DRIVE (drive), NULL);
     194  
     195    iface = G_DRIVE_GET_IFACE (drive);
     196  
     197    if (iface->get_symbolic_icon != NULL)
     198      ret = iface->get_symbolic_icon (drive);
     199    else
     200      ret = g_themed_icon_new_with_default_fallbacks ("drive-removable-media-symbolic");
     201  
     202    return ret;
     203  }
     204  
     205  /**
     206   * g_drive_has_volumes:
     207   * @drive: a #GDrive.
     208   * 
     209   * Check if @drive has any mountable volumes.
     210   * 
     211   * Returns: %TRUE if the @drive contains volumes, %FALSE otherwise.
     212   **/
     213  gboolean
     214  g_drive_has_volumes (GDrive *drive)
     215  {
     216    GDriveIface *iface;
     217  
     218    g_return_val_if_fail (G_IS_DRIVE (drive), FALSE);
     219  
     220    iface = G_DRIVE_GET_IFACE (drive);
     221  
     222    return (* iface->has_volumes) (drive);
     223  }
     224  
     225  /**
     226   * g_drive_get_volumes:
     227   * @drive: a #GDrive.
     228   * 
     229   * Get a list of mountable volumes for @drive.
     230   *
     231   * The returned list should be freed with g_list_free(), after
     232   * its elements have been unreffed with g_object_unref().
     233   * 
     234   * Returns: (element-type GVolume) (transfer full): #GList containing any #GVolume objects on the given @drive.
     235   **/
     236  GList *
     237  g_drive_get_volumes (GDrive *drive)
     238  {
     239    GDriveIface *iface;
     240  
     241    g_return_val_if_fail (G_IS_DRIVE (drive), NULL);
     242  
     243    iface = G_DRIVE_GET_IFACE (drive);
     244  
     245    return (* iface->get_volumes) (drive);
     246  }
     247  
     248  /**
     249   * g_drive_is_media_check_automatic:
     250   * @drive: a #GDrive.
     251   * 
     252   * Checks if @drive is capable of automatically detecting media changes.
     253   * 
     254   * Returns: %TRUE if the @drive is capable of automatically detecting
     255   *     media changes, %FALSE otherwise.
     256   **/
     257  gboolean
     258  g_drive_is_media_check_automatic (GDrive *drive)
     259  {
     260    GDriveIface *iface;
     261  
     262    g_return_val_if_fail (G_IS_DRIVE (drive), FALSE);
     263  
     264    iface = G_DRIVE_GET_IFACE (drive);
     265  
     266    return (* iface->is_media_check_automatic) (drive);
     267  }
     268  
     269  /**
     270   * g_drive_is_removable:
     271   * @drive: a #GDrive.
     272   *
     273   * Checks if the #GDrive and/or its media is considered removable by the user.
     274   * See g_drive_is_media_removable().
     275   *
     276   * Returns: %TRUE if @drive and/or its media is considered removable, %FALSE otherwise.
     277   *
     278   * Since: 2.50
     279   **/
     280  gboolean
     281  g_drive_is_removable (GDrive *drive)
     282  {
     283    GDriveIface *iface;
     284  
     285    g_return_val_if_fail (G_IS_DRIVE (drive), FALSE);
     286  
     287    iface = G_DRIVE_GET_IFACE (drive);
     288    if (iface->is_removable != NULL)
     289      return iface->is_removable (drive);
     290  
     291    return FALSE;
     292  }
     293  
     294  /**
     295   * g_drive_is_media_removable:
     296   * @drive: a #GDrive.
     297   * 
     298   * Checks if the @drive supports removable media.
     299   * 
     300   * Returns: %TRUE if @drive supports removable media, %FALSE otherwise.
     301   **/
     302  gboolean
     303  g_drive_is_media_removable (GDrive *drive)
     304  {
     305    GDriveIface *iface;
     306  
     307    g_return_val_if_fail (G_IS_DRIVE (drive), FALSE);
     308  
     309    iface = G_DRIVE_GET_IFACE (drive);
     310  
     311    return (* iface->is_media_removable) (drive);
     312  }
     313  
     314  /**
     315   * g_drive_has_media:
     316   * @drive: a #GDrive.
     317   * 
     318   * Checks if the @drive has media. Note that the OS may not be polling
     319   * the drive for media changes; see g_drive_is_media_check_automatic()
     320   * for more details.
     321   * 
     322   * Returns: %TRUE if @drive has media, %FALSE otherwise.
     323   **/
     324  gboolean
     325  g_drive_has_media (GDrive *drive)
     326  {
     327    GDriveIface *iface;
     328  
     329    g_return_val_if_fail (G_IS_DRIVE (drive), FALSE);
     330  
     331    iface = G_DRIVE_GET_IFACE (drive);
     332  
     333    return (* iface->has_media) (drive);
     334  }
     335  
     336  /**
     337   * g_drive_can_eject:
     338   * @drive: a #GDrive.
     339   * 
     340   * Checks if a drive can be ejected.
     341   * 
     342   * Returns: %TRUE if the @drive can be ejected, %FALSE otherwise.
     343   **/
     344  gboolean
     345  g_drive_can_eject (GDrive *drive)
     346  {
     347    GDriveIface *iface;
     348  
     349    g_return_val_if_fail (G_IS_DRIVE (drive), FALSE);
     350  
     351    iface = G_DRIVE_GET_IFACE (drive);
     352  
     353    if (iface->can_eject == NULL)
     354      return FALSE;
     355  
     356    return (* iface->can_eject) (drive);
     357  }
     358  
     359  /**
     360   * g_drive_can_poll_for_media:
     361   * @drive: a #GDrive.
     362   * 
     363   * Checks if a drive can be polled for media changes.
     364   * 
     365   * Returns: %TRUE if the @drive can be polled for media changes,
     366   *     %FALSE otherwise.
     367   **/
     368  gboolean
     369  g_drive_can_poll_for_media (GDrive *drive)
     370  {
     371    GDriveIface *iface;
     372  
     373    g_return_val_if_fail (G_IS_DRIVE (drive), FALSE);
     374  
     375    iface = G_DRIVE_GET_IFACE (drive);
     376  
     377    if (iface->poll_for_media == NULL)
     378      return FALSE;
     379  
     380    return (* iface->can_poll_for_media) (drive);
     381  }
     382  
     383  /**
     384   * g_drive_eject:
     385   * @drive: a #GDrive.
     386   * @flags: flags affecting the unmount if required for eject
     387   * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore.
     388   * @callback: (nullable): a #GAsyncReadyCallback, or %NULL.
     389   * @user_data: user data to pass to @callback
     390   * 
     391   * Asynchronously ejects a drive.
     392   *
     393   * When the operation is finished, @callback will be called.
     394   * You can then call g_drive_eject_finish() to obtain the
     395   * result of the operation.
     396   *
     397   * Deprecated: 2.22: Use g_drive_eject_with_operation() instead.
     398   **/
     399  void
     400  g_drive_eject (GDrive              *drive,
     401  	       GMountUnmountFlags   flags,
     402  	       GCancellable        *cancellable,
     403  	       GAsyncReadyCallback  callback,
     404  	       gpointer             user_data)
     405  {
     406    GDriveIface *iface;
     407  
     408    g_return_if_fail (G_IS_DRIVE (drive));
     409  
     410    iface = G_DRIVE_GET_IFACE (drive);
     411  
     412    if (iface->eject == NULL)
     413      {
     414        g_task_report_new_error (drive, callback, user_data,
     415                                 g_drive_eject_with_operation,
     416                                 G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
     417                                 _("drive doesn’t implement eject"));
     418        return;
     419      }
     420    
     421    (* iface->eject) (drive, flags, cancellable, callback, user_data);
     422  }
     423  
     424  /**
     425   * g_drive_eject_finish:
     426   * @drive: a #GDrive.
     427   * @result: a #GAsyncResult.
     428   * @error: a #GError, or %NULL
     429   * 
     430   * Finishes ejecting a drive.
     431   * 
     432   * Returns: %TRUE if the drive has been ejected successfully,
     433   *     %FALSE otherwise.
     434   *
     435   * Deprecated: 2.22: Use g_drive_eject_with_operation_finish() instead.
     436   **/
     437  gboolean
     438  g_drive_eject_finish (GDrive        *drive,
     439  		      GAsyncResult  *result,
     440  		      GError       **error)
     441  {
     442    GDriveIface *iface;
     443  
     444    g_return_val_if_fail (G_IS_DRIVE (drive), FALSE);
     445    g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
     446  
     447    if (g_async_result_legacy_propagate_error (result, error))
     448      return FALSE;
     449    else if (g_async_result_is_tagged (result, g_drive_eject_with_operation))
     450      return g_task_propagate_boolean (G_TASK (result), error);
     451  
     452    iface = G_DRIVE_GET_IFACE (drive);
     453    
     454    return (* iface->eject_finish) (drive, result, error);
     455  }
     456  
     457  /**
     458   * g_drive_eject_with_operation:
     459   * @drive: a #GDrive.
     460   * @flags: flags affecting the unmount if required for eject
     461   * @mount_operation: (nullable): a #GMountOperation or %NULL to avoid
     462   *     user interaction.
     463   * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore.
     464   * @callback: (nullable): a #GAsyncReadyCallback, or %NULL.
     465   * @user_data: user data passed to @callback.
     466   *
     467   * Ejects a drive. This is an asynchronous operation, and is
     468   * finished by calling g_drive_eject_with_operation_finish() with the @drive
     469   * and #GAsyncResult data returned in the @callback.
     470   *
     471   * Since: 2.22
     472   **/
     473  void
     474  g_drive_eject_with_operation (GDrive              *drive,
     475                                GMountUnmountFlags   flags,
     476                                GMountOperation     *mount_operation,
     477                                GCancellable        *cancellable,
     478                                GAsyncReadyCallback  callback,
     479                                gpointer             user_data)
     480  {
     481    GDriveIface *iface;
     482  
     483    g_return_if_fail (G_IS_DRIVE (drive));
     484  
     485    iface = G_DRIVE_GET_IFACE (drive);
     486  
     487    if (iface->eject == NULL && iface->eject_with_operation == NULL)
     488      {
     489        g_task_report_new_error (drive, callback, user_data,
     490                                 g_drive_eject_with_operation,
     491                                 G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
     492                                 /* Translators: This is an error
     493                                  * message for drive objects that
     494                                  * don't implement any of eject or eject_with_operation. */
     495                                 _("drive doesn’t implement eject or eject_with_operation"));
     496        return;
     497      }
     498  
     499    if (iface->eject_with_operation != NULL)
     500      (* iface->eject_with_operation) (drive, flags, mount_operation, cancellable, callback, user_data);
     501    else
     502      (* iface->eject) (drive, flags, cancellable, callback, user_data);
     503  }
     504  
     505  /**
     506   * g_drive_eject_with_operation_finish:
     507   * @drive: a #GDrive.
     508   * @result: a #GAsyncResult.
     509   * @error: a #GError location to store the error occurring, or %NULL to
     510   *     ignore.
     511   *
     512   * Finishes ejecting a drive. If any errors occurred during the operation,
     513   * @error will be set to contain the errors and %FALSE will be returned.
     514   *
     515   * Returns: %TRUE if the drive was successfully ejected. %FALSE otherwise.
     516   *
     517   * Since: 2.22
     518   **/
     519  gboolean
     520  g_drive_eject_with_operation_finish (GDrive        *drive,
     521                                       GAsyncResult  *result,
     522                                       GError       **error)
     523  {
     524    GDriveIface *iface;
     525  
     526    g_return_val_if_fail (G_IS_DRIVE (drive), FALSE);
     527    g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
     528  
     529    if (g_async_result_legacy_propagate_error (result, error))
     530      return FALSE;
     531    else if (g_async_result_is_tagged (result, g_drive_eject_with_operation))
     532      return g_task_propagate_boolean (G_TASK (result), error);
     533  
     534    iface = G_DRIVE_GET_IFACE (drive);
     535    if (iface->eject_with_operation_finish != NULL)
     536      return (* iface->eject_with_operation_finish) (drive, result, error);
     537    else
     538      return (* iface->eject_finish) (drive, result, error);
     539  }
     540  
     541  /**
     542   * g_drive_poll_for_media:
     543   * @drive: a #GDrive.
     544   * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore.
     545   * @callback: (nullable): a #GAsyncReadyCallback, or %NULL.
     546   * @user_data: user data to pass to @callback
     547   * 
     548   * Asynchronously polls @drive to see if media has been inserted or removed.
     549   * 
     550   * When the operation is finished, @callback will be called.
     551   * You can then call g_drive_poll_for_media_finish() to obtain the
     552   * result of the operation.
     553   **/
     554  void
     555  g_drive_poll_for_media (GDrive              *drive,
     556                          GCancellable        *cancellable,
     557                          GAsyncReadyCallback  callback,
     558                          gpointer             user_data)
     559  {
     560    GDriveIface *iface;
     561  
     562    g_return_if_fail (G_IS_DRIVE (drive));
     563  
     564    iface = G_DRIVE_GET_IFACE (drive);
     565  
     566    if (iface->poll_for_media == NULL)
     567      {
     568        g_task_report_new_error (drive, callback, user_data,
     569                                 g_drive_poll_for_media,
     570                                 G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
     571                                 _("drive doesn’t implement polling for media"));
     572        return;
     573      }
     574    
     575    (* iface->poll_for_media) (drive, cancellable, callback, user_data);
     576  }
     577  
     578  /**
     579   * g_drive_poll_for_media_finish:
     580   * @drive: a #GDrive.
     581   * @result: a #GAsyncResult.
     582   * @error: a #GError, or %NULL
     583   * 
     584   * Finishes an operation started with g_drive_poll_for_media() on a drive.
     585   * 
     586   * Returns: %TRUE if the drive has been poll_for_mediaed successfully,
     587   *     %FALSE otherwise.
     588   **/
     589  gboolean
     590  g_drive_poll_for_media_finish (GDrive        *drive,
     591                                 GAsyncResult  *result,
     592                                 GError       **error)
     593  {
     594    GDriveIface *iface;
     595  
     596    g_return_val_if_fail (G_IS_DRIVE (drive), FALSE);
     597    g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
     598  
     599    if (g_async_result_legacy_propagate_error (result, error))
     600      return FALSE;
     601    else if (g_async_result_is_tagged (result, g_drive_poll_for_media))
     602      return g_task_propagate_boolean (G_TASK (result), error);
     603  
     604    iface = G_DRIVE_GET_IFACE (drive);
     605    
     606    return (* iface->poll_for_media_finish) (drive, result, error);
     607  }
     608  
     609  /**
     610   * g_drive_get_identifier:
     611   * @drive: a #GDrive
     612   * @kind: the kind of identifier to return
     613   *
     614   * Gets the identifier of the given kind for @drive. The only
     615   * identifier currently available is
     616   * %G_DRIVE_IDENTIFIER_KIND_UNIX_DEVICE.
     617   *
     618   * Returns: (nullable) (transfer full): a newly allocated string containing the
     619   *     requested identifier, or %NULL if the #GDrive
     620   *     doesn't have this kind of identifier.
     621   */
     622  char *
     623  g_drive_get_identifier (GDrive     *drive,
     624  			const char *kind)
     625  {
     626    GDriveIface *iface;
     627  
     628    g_return_val_if_fail (G_IS_DRIVE (drive), NULL);
     629    g_return_val_if_fail (kind != NULL, NULL);
     630  
     631    iface = G_DRIVE_GET_IFACE (drive);
     632  
     633    if (iface->get_identifier == NULL)
     634      return NULL;
     635    
     636    return (* iface->get_identifier) (drive, kind);
     637  }
     638  
     639  /**
     640   * g_drive_enumerate_identifiers:
     641   * @drive: a #GDrive
     642   *
     643   * Gets the kinds of identifiers that @drive has. 
     644   * Use g_drive_get_identifier() to obtain the identifiers
     645   * themselves.
     646   *
     647   * Returns: (transfer full) (array zero-terminated=1): a %NULL-terminated
     648   *     array of strings containing kinds of identifiers. Use g_strfreev()
     649   *     to free.
     650   */
     651  char **
     652  g_drive_enumerate_identifiers (GDrive *drive)
     653  {
     654    GDriveIface *iface;
     655  
     656    g_return_val_if_fail (G_IS_DRIVE (drive), NULL);
     657    iface = G_DRIVE_GET_IFACE (drive);
     658  
     659    if (iface->enumerate_identifiers == NULL)
     660      return NULL;
     661    
     662    return (* iface->enumerate_identifiers) (drive);
     663  }
     664  
     665  /**
     666   * g_drive_get_start_stop_type:
     667   * @drive: a #GDrive.
     668   *
     669   * Gets a hint about how a drive can be started/stopped.
     670   *
     671   * Returns: A value from the #GDriveStartStopType enumeration.
     672   *
     673   * Since: 2.22
     674   */
     675  GDriveStartStopType
     676  g_drive_get_start_stop_type (GDrive *drive)
     677  {
     678    GDriveIface *iface;
     679  
     680    g_return_val_if_fail (G_IS_DRIVE (drive), FALSE);
     681  
     682    iface = G_DRIVE_GET_IFACE (drive);
     683  
     684    if (iface->get_start_stop_type == NULL)
     685      return G_DRIVE_START_STOP_TYPE_UNKNOWN;
     686  
     687    return (* iface->get_start_stop_type) (drive);
     688  }
     689  
     690  
     691  /**
     692   * g_drive_can_start:
     693   * @drive: a #GDrive.
     694   *
     695   * Checks if a drive can be started.
     696   *
     697   * Returns: %TRUE if the @drive can be started, %FALSE otherwise.
     698   *
     699   * Since: 2.22
     700   */
     701  gboolean
     702  g_drive_can_start (GDrive *drive)
     703  {
     704    GDriveIface *iface;
     705  
     706    g_return_val_if_fail (G_IS_DRIVE (drive), FALSE);
     707  
     708    iface = G_DRIVE_GET_IFACE (drive);
     709  
     710    if (iface->can_start == NULL)
     711      return FALSE;
     712  
     713    return (* iface->can_start) (drive);
     714  }
     715  
     716  /**
     717   * g_drive_can_start_degraded:
     718   * @drive: a #GDrive.
     719   *
     720   * Checks if a drive can be started degraded.
     721   *
     722   * Returns: %TRUE if the @drive can be started degraded, %FALSE otherwise.
     723   *
     724   * Since: 2.22
     725   */
     726  gboolean
     727  g_drive_can_start_degraded (GDrive *drive)
     728  {
     729    GDriveIface *iface;
     730  
     731    g_return_val_if_fail (G_IS_DRIVE (drive), FALSE);
     732  
     733    iface = G_DRIVE_GET_IFACE (drive);
     734  
     735    if (iface->can_start_degraded == NULL)
     736      return FALSE;
     737  
     738    return (* iface->can_start_degraded) (drive);
     739  }
     740  
     741  /**
     742   * g_drive_start:
     743   * @drive: a #GDrive.
     744   * @flags: flags affecting the start operation.
     745   * @mount_operation: (nullable): a #GMountOperation or %NULL to avoid
     746   *     user interaction.
     747   * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore.
     748   * @callback: (nullable): a #GAsyncReadyCallback, or %NULL.
     749   * @user_data: user data to pass to @callback
     750   *
     751   * Asynchronously starts a drive.
     752   *
     753   * When the operation is finished, @callback will be called.
     754   * You can then call g_drive_start_finish() to obtain the
     755   * result of the operation.
     756   *
     757   * Since: 2.22
     758   */
     759  void
     760  g_drive_start (GDrive              *drive,
     761                 GDriveStartFlags     flags,
     762                 GMountOperation     *mount_operation,
     763                 GCancellable        *cancellable,
     764                 GAsyncReadyCallback  callback,
     765                 gpointer             user_data)
     766  {
     767    GDriveIface *iface;
     768  
     769    g_return_if_fail (G_IS_DRIVE (drive));
     770  
     771    iface = G_DRIVE_GET_IFACE (drive);
     772  
     773    if (iface->start == NULL)
     774      {
     775        g_task_report_new_error (drive, callback, user_data,
     776                                 g_drive_start,
     777                                 G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
     778                                 _("drive doesn’t implement start"));
     779        return;
     780      }
     781  
     782    (* iface->start) (drive, flags, mount_operation, cancellable, callback, user_data);
     783  }
     784  
     785  /**
     786   * g_drive_start_finish:
     787   * @drive: a #GDrive.
     788   * @result: a #GAsyncResult.
     789   * @error: a #GError, or %NULL
     790   *
     791   * Finishes starting a drive.
     792   *
     793   * Returns: %TRUE if the drive has been started successfully,
     794   *     %FALSE otherwise.
     795   *
     796   * Since: 2.22
     797   */
     798  gboolean
     799  g_drive_start_finish (GDrive         *drive,
     800                        GAsyncResult   *result,
     801                        GError        **error)
     802  {
     803    GDriveIface *iface;
     804  
     805    g_return_val_if_fail (G_IS_DRIVE (drive), FALSE);
     806    g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
     807  
     808    if (g_async_result_legacy_propagate_error (result, error))
     809      return FALSE;
     810    else if (g_async_result_is_tagged (result, g_drive_start))
     811      return g_task_propagate_boolean (G_TASK (result), error);
     812  
     813    iface = G_DRIVE_GET_IFACE (drive);
     814  
     815    return (* iface->start_finish) (drive, result, error);
     816  }
     817  
     818  /**
     819   * g_drive_can_stop:
     820   * @drive: a #GDrive.
     821   *
     822   * Checks if a drive can be stopped.
     823   *
     824   * Returns: %TRUE if the @drive can be stopped, %FALSE otherwise.
     825   *
     826   * Since: 2.22
     827   */
     828  gboolean
     829  g_drive_can_stop (GDrive *drive)
     830  {
     831    GDriveIface *iface;
     832  
     833    g_return_val_if_fail (G_IS_DRIVE (drive), FALSE);
     834  
     835    iface = G_DRIVE_GET_IFACE (drive);
     836  
     837    if (iface->can_stop == NULL)
     838      return FALSE;
     839  
     840    return (* iface->can_stop) (drive);
     841  }
     842  
     843  /**
     844   * g_drive_stop:
     845   * @drive: a #GDrive.
     846   * @flags: flags affecting the unmount if required for stopping.
     847   * @mount_operation: (nullable): a #GMountOperation or %NULL to avoid
     848   *     user interaction.
     849   * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore.
     850   * @callback: (nullable): a #GAsyncReadyCallback, or %NULL.
     851   * @user_data: user data to pass to @callback
     852   *
     853   * Asynchronously stops a drive.
     854   *
     855   * When the operation is finished, @callback will be called.
     856   * You can then call g_drive_stop_finish() to obtain the
     857   * result of the operation.
     858   *
     859   * Since: 2.22
     860   */
     861  void
     862  g_drive_stop (GDrive               *drive,
     863                GMountUnmountFlags    flags,
     864                GMountOperation      *mount_operation,
     865                GCancellable         *cancellable,
     866                GAsyncReadyCallback   callback,
     867                gpointer              user_data)
     868  {
     869    GDriveIface *iface;
     870  
     871    g_return_if_fail (G_IS_DRIVE (drive));
     872  
     873    iface = G_DRIVE_GET_IFACE (drive);
     874  
     875    if (iface->stop == NULL)
     876      {
     877        g_task_report_new_error (drive, callback, user_data,
     878                                 g_drive_start,
     879                                 G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
     880                                 _("drive doesn’t implement stop"));
     881        return;
     882      }
     883  
     884    (* iface->stop) (drive, flags, mount_operation, cancellable, callback, user_data);
     885  }
     886  
     887  /**
     888   * g_drive_stop_finish:
     889   * @drive: a #GDrive.
     890   * @result: a #GAsyncResult.
     891   * @error: a #GError, or %NULL
     892   *
     893   * Finishes stopping a drive.
     894   *
     895   * Returns: %TRUE if the drive has been stopped successfully,
     896   *     %FALSE otherwise.
     897   *
     898   * Since: 2.22
     899   */
     900  gboolean
     901  g_drive_stop_finish (GDrive        *drive,
     902                       GAsyncResult  *result,
     903                       GError       **error)
     904  {
     905    GDriveIface *iface;
     906  
     907    g_return_val_if_fail (G_IS_DRIVE (drive), FALSE);
     908    g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
     909  
     910    if (g_async_result_legacy_propagate_error (result, error))
     911      return FALSE;
     912    else if (g_async_result_is_tagged (result, g_drive_start))
     913      return g_task_propagate_boolean (G_TASK (result), error);
     914  
     915    iface = G_DRIVE_GET_IFACE (drive);
     916  
     917    return (* iface->stop_finish) (drive, result, error);
     918  }
     919  
     920  /**
     921   * g_drive_get_sort_key:
     922   * @drive: A #GDrive.
     923   *
     924   * Gets the sort key for @drive, if any.
     925   *
     926   * Returns: (nullable): Sorting key for @drive or %NULL if no such key is available.
     927   *
     928   * Since: 2.32
     929   */
     930  const gchar *
     931  g_drive_get_sort_key (GDrive  *drive)
     932  {
     933    const gchar *ret = NULL;
     934    GDriveIface *iface;
     935  
     936    g_return_val_if_fail (G_IS_DRIVE (drive), NULL);
     937  
     938    iface = G_DRIVE_GET_IFACE (drive);
     939    if (iface->get_sort_key != NULL)
     940      ret = iface->get_sort_key (drive);
     941  
     942    return ret;
     943  }