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