Improve .gitignore
[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_IS_SIMPLE_ASYNC_RESULT (result))
395     {
396       GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
397       if (g_simple_async_result_propagate_error (simple, error))
398         return FALSE;
399     }
400   
401   iface = G_DRIVE_GET_IFACE (drive);
402   
403   return (* iface->eject_finish) (drive, result, error);
404 }
405
406 /**
407  * g_drive_eject_with_operation:
408  * @drive: a #GDrive.
409  * @flags: flags affecting the unmount if required for eject
410  * @mount_operation: (allow-none): a #GMountOperation or %NULL to avoid
411  *     user interaction.
412  * @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore.
413  * @callback: (allow-none): a #GAsyncReadyCallback, or %NULL.
414  * @user_data: user data passed to @callback.
415  *
416  * Ejects a drive. This is an asynchronous operation, and is
417  * finished by calling g_drive_eject_with_operation_finish() with the @drive
418  * and #GAsyncResult data returned in the @callback.
419  *
420  * Since: 2.22
421  **/
422 void
423 g_drive_eject_with_operation (GDrive              *drive,
424                               GMountUnmountFlags   flags,
425                               GMountOperation     *mount_operation,
426                               GCancellable        *cancellable,
427                               GAsyncReadyCallback  callback,
428                               gpointer             user_data)
429 {
430   GDriveIface *iface;
431
432   g_return_if_fail (G_IS_DRIVE (drive));
433
434   iface = G_DRIVE_GET_IFACE (drive);
435
436   if (iface->eject == NULL && iface->eject_with_operation == NULL)
437     {
438       g_simple_async_report_error_in_idle (G_OBJECT (drive),
439                                            callback, user_data,
440                                            G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
441                                            /* Translators: This is an error
442                                             * message for drive objects that
443                                             * don't implement any of eject or eject_with_operation. */
444                                            _("drive doesn't implement eject or eject_with_operation"));
445       return;
446     }
447
448   if (iface->eject_with_operation != NULL)
449     (* iface->eject_with_operation) (drive, flags, mount_operation, cancellable, callback, user_data);
450   else
451     (* iface->eject) (drive, flags, cancellable, callback, user_data);
452 }
453
454 /**
455  * g_drive_eject_with_operation_finish:
456  * @drive: a #GDrive.
457  * @result: a #GAsyncResult.
458  * @error: a #GError location to store the error occuring, or %NULL to
459  *     ignore.
460  *
461  * Finishes ejecting a drive. If any errors occurred during the operation,
462  * @error will be set to contain the errors and %FALSE will be returned.
463  *
464  * Returns: %TRUE if the drive was successfully ejected. %FALSE otherwise.
465  *
466  * Since: 2.22
467  **/
468 gboolean
469 g_drive_eject_with_operation_finish (GDrive        *drive,
470                                      GAsyncResult  *result,
471                                      GError       **error)
472 {
473   GDriveIface *iface;
474
475   g_return_val_if_fail (G_IS_DRIVE (drive), FALSE);
476   g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
477
478   if (G_IS_SIMPLE_ASYNC_RESULT (result))
479     {
480       GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
481       if (g_simple_async_result_propagate_error (simple, error))
482         return FALSE;
483     }
484
485   iface = G_DRIVE_GET_IFACE (drive);
486   if (iface->eject_with_operation_finish != NULL)
487     return (* iface->eject_with_operation_finish) (drive, result, error);
488   else
489     return (* iface->eject_finish) (drive, result, error);
490 }
491
492 /**
493  * g_drive_poll_for_media:
494  * @drive: a #GDrive.
495  * @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore.
496  * @callback: (allow-none): a #GAsyncReadyCallback, or %NULL.
497  * @user_data: user data to pass to @callback
498  * 
499  * Asynchronously polls @drive to see if media has been inserted or removed.
500  * 
501  * When the operation is finished, @callback will be called.
502  * You can then call g_drive_poll_for_media_finish() to obtain the
503  * result of the operation.
504  **/
505 void
506 g_drive_poll_for_media (GDrive              *drive,
507                         GCancellable        *cancellable,
508                         GAsyncReadyCallback  callback,
509                         gpointer             user_data)
510 {
511   GDriveIface *iface;
512
513   g_return_if_fail (G_IS_DRIVE (drive));
514
515   iface = G_DRIVE_GET_IFACE (drive);
516
517   if (iface->poll_for_media == NULL)
518     {
519       g_simple_async_report_error_in_idle (G_OBJECT (drive), callback, user_data,
520                                            G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
521                                            _("drive doesn't implement polling for media"));
522       
523       return;
524     }
525   
526   (* iface->poll_for_media) (drive, cancellable, callback, user_data);
527 }
528
529 /**
530  * g_drive_poll_for_media_finish:
531  * @drive: a #GDrive.
532  * @result: a #GAsyncResult.
533  * @error: a #GError, or %NULL
534  * 
535  * Finishes an operation started with g_drive_poll_for_media() on a drive.
536  * 
537  * Returns: %TRUE if the drive has been poll_for_mediaed successfully,
538  *     %FALSE otherwise.
539  **/
540 gboolean
541 g_drive_poll_for_media_finish (GDrive        *drive,
542                                GAsyncResult  *result,
543                                GError       **error)
544 {
545   GDriveIface *iface;
546
547   g_return_val_if_fail (G_IS_DRIVE (drive), FALSE);
548   g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
549
550   if (G_IS_SIMPLE_ASYNC_RESULT (result))
551     {
552       GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
553       if (g_simple_async_result_propagate_error (simple, error))
554         return FALSE;
555     }
556   
557   iface = G_DRIVE_GET_IFACE (drive);
558   
559   return (* iface->poll_for_media_finish) (drive, result, error);
560 }
561
562 /**
563  * g_drive_get_identifier:
564  * @drive: a #GDrive
565  * @kind: the kind of identifier to return
566  *
567  * Gets the identifier of the given kind for @drive.
568  *
569  * Returns: a newly allocated string containing the
570  *     requested identfier, or %NULL if the #GDrive
571  *     doesn't have this kind of identifier.
572  */
573 char *
574 g_drive_get_identifier (GDrive     *drive,
575                         const char *kind)
576 {
577   GDriveIface *iface;
578
579   g_return_val_if_fail (G_IS_DRIVE (drive), NULL);
580   g_return_val_if_fail (kind != NULL, NULL);
581
582   iface = G_DRIVE_GET_IFACE (drive);
583
584   if (iface->get_identifier == NULL)
585     return NULL;
586   
587   return (* iface->get_identifier) (drive, kind);
588 }
589
590 /**
591  * g_drive_enumerate_identifiers:
592  * @drive: a #GDrive
593  *
594  * Gets the kinds of identifiers that @drive has. 
595  * Use g_drive_get_identifer() to obtain the identifiers
596  * themselves.
597  *
598  * Returns: (transfer full) (array zero-terminated=1): a %NULL-terminated
599  *     array of strings containing kinds of identifiers. Use g_strfreev()
600  *     to free.
601  */
602 char **
603 g_drive_enumerate_identifiers (GDrive *drive)
604 {
605   GDriveIface *iface;
606
607   g_return_val_if_fail (G_IS_DRIVE (drive), NULL);
608   iface = G_DRIVE_GET_IFACE (drive);
609
610   if (iface->enumerate_identifiers == NULL)
611     return NULL;
612   
613   return (* iface->enumerate_identifiers) (drive);
614 }
615
616 /**
617  * g_drive_get_start_stop_type:
618  * @drive: a #GDrive.
619  *
620  * Gets a hint about how a drive can be started/stopped.
621  *
622  * Returns: A value from the #GDriveStartStopType enumeration.
623  *
624  * Since: 2.22
625  */
626 GDriveStartStopType
627 g_drive_get_start_stop_type (GDrive *drive)
628 {
629   GDriveIface *iface;
630
631   g_return_val_if_fail (G_IS_DRIVE (drive), FALSE);
632
633   iface = G_DRIVE_GET_IFACE (drive);
634
635   if (iface->get_start_stop_type == NULL)
636     return G_DRIVE_START_STOP_TYPE_UNKNOWN;
637
638   return (* iface->get_start_stop_type) (drive);
639 }
640
641
642 /**
643  * g_drive_can_start:
644  * @drive: a #GDrive.
645  *
646  * Checks if a drive can be started.
647  *
648  * Returns: %TRUE if the @drive can be started, %FALSE otherwise.
649  *
650  * Since: 2.22
651  */
652 gboolean
653 g_drive_can_start (GDrive *drive)
654 {
655   GDriveIface *iface;
656
657   g_return_val_if_fail (G_IS_DRIVE (drive), FALSE);
658
659   iface = G_DRIVE_GET_IFACE (drive);
660
661   if (iface->can_start == NULL)
662     return FALSE;
663
664   return (* iface->can_start) (drive);
665 }
666
667 /**
668  * g_drive_can_start_degraded:
669  * @drive: a #GDrive.
670  *
671  * Checks if a drive can be started degraded.
672  *
673  * Returns: %TRUE if the @drive can be started degraded, %FALSE otherwise.
674  *
675  * Since: 2.22
676  */
677 gboolean
678 g_drive_can_start_degraded (GDrive *drive)
679 {
680   GDriveIface *iface;
681
682   g_return_val_if_fail (G_IS_DRIVE (drive), FALSE);
683
684   iface = G_DRIVE_GET_IFACE (drive);
685
686   if (iface->can_start_degraded == NULL)
687     return FALSE;
688
689   return (* iface->can_start_degraded) (drive);
690 }
691
692 /**
693  * g_drive_start:
694  * @drive: a #GDrive.
695  * @flags: flags affecting the start operation.
696  * @mount_operation: (allow-none): a #GMountOperation or %NULL to avoid
697  *     user interaction.
698  * @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore.
699  * @callback: (allow-none): a #GAsyncReadyCallback, or %NULL.
700  * @user_data: user data to pass to @callback
701  *
702  * Asynchronously starts a drive.
703  *
704  * When the operation is finished, @callback will be called.
705  * You can then call g_drive_start_finish() to obtain the
706  * result of the operation.
707  *
708  * Since: 2.22
709  */
710 void
711 g_drive_start (GDrive              *drive,
712                GDriveStartFlags     flags,
713                GMountOperation     *mount_operation,
714                GCancellable        *cancellable,
715                GAsyncReadyCallback  callback,
716                gpointer             user_data)
717 {
718   GDriveIface *iface;
719
720   g_return_if_fail (G_IS_DRIVE (drive));
721
722   iface = G_DRIVE_GET_IFACE (drive);
723
724   if (iface->start == NULL)
725     {
726       g_simple_async_report_error_in_idle (G_OBJECT (drive), callback, user_data,
727                                            G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
728                                            _("drive doesn't implement start"));
729       return;
730     }
731
732   (* iface->start) (drive, flags, mount_operation, cancellable, callback, user_data);
733 }
734
735 /**
736  * g_drive_start_finish:
737  * @drive: a #GDrive.
738  * @result: a #GAsyncResult.
739  * @error: a #GError, or %NULL
740  *
741  * Finishes starting a drive.
742  *
743  * Returns: %TRUE if the drive has been started successfully,
744  *     %FALSE otherwise.
745  *
746  * Since: 2.22
747  */
748 gboolean
749 g_drive_start_finish (GDrive         *drive,
750                       GAsyncResult   *result,
751                       GError        **error)
752 {
753   GDriveIface *iface;
754
755   g_return_val_if_fail (G_IS_DRIVE (drive), FALSE);
756   g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
757
758   if (G_IS_SIMPLE_ASYNC_RESULT (result))
759     {
760       GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
761       if (g_simple_async_result_propagate_error (simple, error))
762         return FALSE;
763     }
764
765   iface = G_DRIVE_GET_IFACE (drive);
766
767   return (* iface->start_finish) (drive, result, error);
768 }
769
770 /**
771  * g_drive_can_stop:
772  * @drive: a #GDrive.
773  *
774  * Checks if a drive can be stopped.
775  *
776  * Returns: %TRUE if the @drive can be stopped, %FALSE otherwise.
777  *
778  * Since: 2.22
779  */
780 gboolean
781 g_drive_can_stop (GDrive *drive)
782 {
783   GDriveIface *iface;
784
785   g_return_val_if_fail (G_IS_DRIVE (drive), FALSE);
786
787   iface = G_DRIVE_GET_IFACE (drive);
788
789   if (iface->can_stop == NULL)
790     return FALSE;
791
792   return (* iface->can_stop) (drive);
793 }
794
795 /**
796  * g_drive_stop:
797  * @drive: a #GDrive.
798  * @flags: flags affecting the unmount if required for stopping.
799  * @mount_operation: (allow-none): a #GMountOperation or %NULL to avoid
800  *     user interaction.
801  * @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore.
802  * @callback: (allow-none): a #GAsyncReadyCallback, or %NULL.
803  * @user_data: user data to pass to @callback
804  *
805  * Asynchronously stops a drive.
806  *
807  * When the operation is finished, @callback will be called.
808  * You can then call g_drive_stop_finish() to obtain the
809  * result of the operation.
810  *
811  * Since: 2.22
812  */
813 void
814 g_drive_stop (GDrive               *drive,
815               GMountUnmountFlags    flags,
816               GMountOperation      *mount_operation,
817               GCancellable         *cancellable,
818               GAsyncReadyCallback   callback,
819               gpointer              user_data)
820 {
821   GDriveIface *iface;
822
823   g_return_if_fail (G_IS_DRIVE (drive));
824
825   iface = G_DRIVE_GET_IFACE (drive);
826
827   if (iface->stop == NULL)
828     {
829       g_simple_async_report_error_in_idle (G_OBJECT (drive), callback, user_data,
830                                            G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
831                                            _("drive doesn't implement stop"));
832       return;
833     }
834
835   (* iface->stop) (drive, flags, mount_operation, cancellable, callback, user_data);
836 }
837
838 /**
839  * g_drive_stop_finish:
840  * @drive: a #GDrive.
841  * @result: a #GAsyncResult.
842  * @error: a #GError, or %NULL
843  *
844  * Finishes stopping a drive.
845  *
846  * Returns: %TRUE if the drive has been stopped successfully,
847  *     %FALSE otherwise.
848  *
849  * Since: 2.22
850  */
851 gboolean
852 g_drive_stop_finish (GDrive        *drive,
853                      GAsyncResult  *result,
854                      GError       **error)
855 {
856   GDriveIface *iface;
857
858   g_return_val_if_fail (G_IS_DRIVE (drive), FALSE);
859   g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
860
861   if (G_IS_SIMPLE_ASYNC_RESULT (result))
862     {
863       GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
864       if (g_simple_async_result_propagate_error (simple, error))
865         return FALSE;
866     }
867
868   iface = G_DRIVE_GET_IFACE (drive);
869
870   return (* iface->stop_finish) (drive, result, error);
871 }