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