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.1 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, see <http://www.gnu.org/licenses/>.
17  *
18  * Author: Alexander Larsson <alexl@redhat.com>
19  *         David Zeuthen <davidz@redhat.com>
20  */
21 
22 #include "config.h"
23 #include "gdrive.h"
24 #include "gtask.h"
25 #include "gthemedicon.h"
26 #include "gasyncresult.h"
27 #include "gioerror.h"
28 #include "glibintl.h"
29 
30 
31 /**
32  * SECTION:gdrive
33  * @short_description: Drive management
34  * @include: gio/gio.h
35  *
36  * #GDrive - this represent 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 #GVolume 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 g_drive_get_start_stop_type().
59  *
60  * For porting from GnomeVFS note that there is no equivalent of
61  * #GDrive in that API.
62  **/
63 
64 typedef GDriveIface GDriveInterface;
G_DEFINE_INTERFACE(GDrive,g_drive,G_TYPE_OBJECT)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 *
g_drive_get_name(GDrive * drive)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 *
g_drive_get_icon(GDrive * drive)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 *
g_drive_get_symbolic_icon(GDrive * drive)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
g_drive_has_volumes(GDrive * drive)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 *
g_drive_get_volumes(GDrive * drive)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
g_drive_is_media_check_automatic(GDrive * drive)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
g_drive_is_removable(GDrive * drive)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
g_drive_is_media_removable(GDrive * drive)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
g_drive_has_media(GDrive * drive)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
g_drive_can_eject(GDrive * drive)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
g_drive_can_poll_for_media(GDrive * drive)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
g_drive_eject(GDrive * drive,GMountUnmountFlags flags,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)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
g_drive_eject_finish(GDrive * drive,GAsyncResult * result,GError ** error)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
g_drive_eject_with_operation(GDrive * drive,GMountUnmountFlags flags,GMountOperation * mount_operation,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)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
g_drive_eject_with_operation_finish(GDrive * drive,GAsyncResult * result,GError ** error)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
g_drive_poll_for_media(GDrive * drive,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)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
g_drive_poll_for_media_finish(GDrive * drive,GAsyncResult * result,GError ** error)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 *
g_drive_get_identifier(GDrive * drive,const char * kind)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 **
g_drive_enumerate_identifiers(GDrive * drive)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
g_drive_get_start_stop_type(GDrive * drive)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
g_drive_can_start(GDrive * drive)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
g_drive_can_start_degraded(GDrive * drive)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
g_drive_start(GDrive * drive,GDriveStartFlags flags,GMountOperation * mount_operation,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)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
g_drive_start_finish(GDrive * drive,GAsyncResult * result,GError ** error)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
g_drive_can_stop(GDrive * drive)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
g_drive_stop(GDrive * drive,GMountUnmountFlags flags,GMountOperation * mount_operation,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)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
g_drive_stop_finish(GDrive * drive,GAsyncResult * result,GError ** error)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 *
g_drive_get_sort_key(GDrive * drive)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 }
944