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; |
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 | signal_flags: G_SIGNAL_RUN_LAST, |
79 | G_STRUCT_OFFSET (GDriveIface, changed), |
80 | NULL, NULL, |
81 | NULL, |
82 | G_TYPE_NONE, n_params: 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 | signal_flags: G_SIGNAL_RUN_LAST, |
96 | G_STRUCT_OFFSET (GDriveIface, disconnected), |
97 | NULL, NULL, |
98 | NULL, |
99 | G_TYPE_NONE, n_params: 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 | signal_flags: G_SIGNAL_RUN_LAST, |
111 | G_STRUCT_OFFSET (GDriveIface, eject_button), |
112 | NULL, NULL, |
113 | NULL, |
114 | G_TYPE_NONE, n_params: 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 | signal_flags: G_SIGNAL_RUN_LAST, |
128 | G_STRUCT_OFFSET (GDriveIface, stop_button), |
129 | NULL, NULL, |
130 | NULL, |
131 | G_TYPE_NONE, n_params: 0); |
132 | } |
133 | |
134 | /** |
135 | * g_drive_get_name: |
136 | * @drive: a #GDrive. |
137 | * |
138 | * Gets the name of @drive. |
139 | * |
140 | * Returns: a string containing @drive's name. The returned |
141 | * string should be freed when no longer needed. |
142 | **/ |
143 | char * |
144 | g_drive_get_name (GDrive *drive) |
145 | { |
146 | GDriveIface *iface; |
147 | |
148 | g_return_val_if_fail (G_IS_DRIVE (drive), NULL); |
149 | |
150 | iface = G_DRIVE_GET_IFACE (drive); |
151 | |
152 | return (* iface->get_name) (drive); |
153 | } |
154 | |
155 | /** |
156 | * g_drive_get_icon: |
157 | * @drive: a #GDrive. |
158 | * |
159 | * Gets the icon for @drive. |
160 | * |
161 | * Returns: (transfer full): #GIcon for the @drive. |
162 | * Free the returned object with g_object_unref(). |
163 | **/ |
164 | GIcon * |
165 | g_drive_get_icon (GDrive *drive) |
166 | { |
167 | GDriveIface *iface; |
168 | |
169 | g_return_val_if_fail (G_IS_DRIVE (drive), NULL); |
170 | |
171 | iface = G_DRIVE_GET_IFACE (drive); |
172 | |
173 | return (* iface->get_icon) (drive); |
174 | } |
175 | |
176 | /** |
177 | * g_drive_get_symbolic_icon: |
178 | * @drive: a #GDrive. |
179 | * |
180 | * Gets the icon for @drive. |
181 | * |
182 | * Returns: (transfer full): symbolic #GIcon for the @drive. |
183 | * Free the returned object with g_object_unref(). |
184 | * |
185 | * Since: 2.34 |
186 | **/ |
187 | GIcon * |
188 | g_drive_get_symbolic_icon (GDrive *drive) |
189 | { |
190 | GDriveIface *iface; |
191 | GIcon *ret; |
192 | |
193 | g_return_val_if_fail (G_IS_DRIVE (drive), NULL); |
194 | |
195 | iface = G_DRIVE_GET_IFACE (drive); |
196 | |
197 | if (iface->get_symbolic_icon != NULL) |
198 | ret = iface->get_symbolic_icon (drive); |
199 | else |
200 | ret = g_themed_icon_new_with_default_fallbacks (iconname: "drive-removable-media-symbolic" ); |
201 | |
202 | return ret; |
203 | } |
204 | |
205 | /** |
206 | * g_drive_has_volumes: |
207 | * @drive: a #GDrive. |
208 | * |
209 | * Check if @drive has any mountable volumes. |
210 | * |
211 | * Returns: %TRUE if the @drive contains volumes, %FALSE otherwise. |
212 | **/ |
213 | gboolean |
214 | g_drive_has_volumes (GDrive *drive) |
215 | { |
216 | GDriveIface *iface; |
217 | |
218 | g_return_val_if_fail (G_IS_DRIVE (drive), FALSE); |
219 | |
220 | iface = G_DRIVE_GET_IFACE (drive); |
221 | |
222 | return (* iface->has_volumes) (drive); |
223 | } |
224 | |
225 | /** |
226 | * g_drive_get_volumes: |
227 | * @drive: a #GDrive. |
228 | * |
229 | * Get a list of mountable volumes for @drive. |
230 | * |
231 | * The returned list should be freed with g_list_free(), after |
232 | * its elements have been unreffed with g_object_unref(). |
233 | * |
234 | * Returns: (element-type GVolume) (transfer full): #GList containing any #GVolume objects on the given @drive. |
235 | **/ |
236 | GList * |
237 | g_drive_get_volumes (GDrive *drive) |
238 | { |
239 | GDriveIface *iface; |
240 | |
241 | g_return_val_if_fail (G_IS_DRIVE (drive), NULL); |
242 | |
243 | iface = G_DRIVE_GET_IFACE (drive); |
244 | |
245 | return (* iface->get_volumes) (drive); |
246 | } |
247 | |
248 | /** |
249 | * g_drive_is_media_check_automatic: |
250 | * @drive: a #GDrive. |
251 | * |
252 | * Checks if @drive is capable of automatically detecting media changes. |
253 | * |
254 | * Returns: %TRUE if the @drive is capable of automatically detecting |
255 | * media changes, %FALSE otherwise. |
256 | **/ |
257 | gboolean |
258 | g_drive_is_media_check_automatic (GDrive *drive) |
259 | { |
260 | GDriveIface *iface; |
261 | |
262 | g_return_val_if_fail (G_IS_DRIVE (drive), FALSE); |
263 | |
264 | iface = G_DRIVE_GET_IFACE (drive); |
265 | |
266 | return (* iface->is_media_check_automatic) (drive); |
267 | } |
268 | |
269 | /** |
270 | * g_drive_is_removable: |
271 | * @drive: a #GDrive. |
272 | * |
273 | * Checks if the #GDrive and/or its media is considered removable by the user. |
274 | * See g_drive_is_media_removable(). |
275 | * |
276 | * Returns: %TRUE if @drive and/or its media is considered removable, %FALSE otherwise. |
277 | * |
278 | * Since: 2.50 |
279 | **/ |
280 | gboolean |
281 | g_drive_is_removable (GDrive *drive) |
282 | { |
283 | GDriveIface *iface; |
284 | |
285 | g_return_val_if_fail (G_IS_DRIVE (drive), FALSE); |
286 | |
287 | iface = G_DRIVE_GET_IFACE (drive); |
288 | if (iface->is_removable != NULL) |
289 | return iface->is_removable (drive); |
290 | |
291 | return FALSE; |
292 | } |
293 | |
294 | /** |
295 | * g_drive_is_media_removable: |
296 | * @drive: a #GDrive. |
297 | * |
298 | * Checks if the @drive supports removable media. |
299 | * |
300 | * Returns: %TRUE if @drive supports removable media, %FALSE otherwise. |
301 | **/ |
302 | gboolean |
303 | g_drive_is_media_removable (GDrive *drive) |
304 | { |
305 | GDriveIface *iface; |
306 | |
307 | g_return_val_if_fail (G_IS_DRIVE (drive), FALSE); |
308 | |
309 | iface = G_DRIVE_GET_IFACE (drive); |
310 | |
311 | return (* iface->is_media_removable) (drive); |
312 | } |
313 | |
314 | /** |
315 | * g_drive_has_media: |
316 | * @drive: a #GDrive. |
317 | * |
318 | * Checks if the @drive has media. Note that the OS may not be polling |
319 | * the drive for media changes; see g_drive_is_media_check_automatic() |
320 | * for more details. |
321 | * |
322 | * Returns: %TRUE if @drive has media, %FALSE otherwise. |
323 | **/ |
324 | gboolean |
325 | g_drive_has_media (GDrive *drive) |
326 | { |
327 | GDriveIface *iface; |
328 | |
329 | g_return_val_if_fail (G_IS_DRIVE (drive), FALSE); |
330 | |
331 | iface = G_DRIVE_GET_IFACE (drive); |
332 | |
333 | return (* iface->has_media) (drive); |
334 | } |
335 | |
336 | /** |
337 | * g_drive_can_eject: |
338 | * @drive: a #GDrive. |
339 | * |
340 | * Checks if a drive can be ejected. |
341 | * |
342 | * Returns: %TRUE if the @drive can be ejected, %FALSE otherwise. |
343 | **/ |
344 | gboolean |
345 | g_drive_can_eject (GDrive *drive) |
346 | { |
347 | GDriveIface *iface; |
348 | |
349 | g_return_val_if_fail (G_IS_DRIVE (drive), FALSE); |
350 | |
351 | iface = G_DRIVE_GET_IFACE (drive); |
352 | |
353 | if (iface->can_eject == NULL) |
354 | return FALSE; |
355 | |
356 | return (* iface->can_eject) (drive); |
357 | } |
358 | |
359 | /** |
360 | * g_drive_can_poll_for_media: |
361 | * @drive: a #GDrive. |
362 | * |
363 | * Checks if a drive can be polled for media changes. |
364 | * |
365 | * Returns: %TRUE if the @drive can be polled for media changes, |
366 | * %FALSE otherwise. |
367 | **/ |
368 | gboolean |
369 | g_drive_can_poll_for_media (GDrive *drive) |
370 | { |
371 | GDriveIface *iface; |
372 | |
373 | g_return_val_if_fail (G_IS_DRIVE (drive), FALSE); |
374 | |
375 | iface = G_DRIVE_GET_IFACE (drive); |
376 | |
377 | if (iface->poll_for_media == NULL) |
378 | return FALSE; |
379 | |
380 | return (* iface->can_poll_for_media) (drive); |
381 | } |
382 | |
383 | /** |
384 | * g_drive_eject: |
385 | * @drive: a #GDrive. |
386 | * @flags: flags affecting the unmount if required for eject |
387 | * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore. |
388 | * @callback: (nullable): a #GAsyncReadyCallback, or %NULL. |
389 | * @user_data: user data to pass to @callback |
390 | * |
391 | * Asynchronously ejects a drive. |
392 | * |
393 | * When the operation is finished, @callback will be called. |
394 | * You can then call g_drive_eject_finish() to obtain the |
395 | * result of the operation. |
396 | * |
397 | * Deprecated: 2.22: Use g_drive_eject_with_operation() instead. |
398 | **/ |
399 | void |
400 | g_drive_eject (GDrive *drive, |
401 | GMountUnmountFlags flags, |
402 | GCancellable *cancellable, |
403 | GAsyncReadyCallback callback, |
404 | gpointer user_data) |
405 | { |
406 | GDriveIface *iface; |
407 | |
408 | g_return_if_fail (G_IS_DRIVE (drive)); |
409 | |
410 | iface = G_DRIVE_GET_IFACE (drive); |
411 | |
412 | if (iface->eject == NULL) |
413 | { |
414 | g_task_report_new_error (source_object: drive, callback, callback_data: user_data, |
415 | source_tag: g_drive_eject_with_operation, |
416 | G_IO_ERROR, code: G_IO_ERROR_NOT_SUPPORTED, |
417 | _("drive doesn’t implement eject" )); |
418 | return; |
419 | } |
420 | |
421 | (* iface->eject) (drive, flags, cancellable, callback, user_data); |
422 | } |
423 | |
424 | /** |
425 | * g_drive_eject_finish: |
426 | * @drive: a #GDrive. |
427 | * @result: a #GAsyncResult. |
428 | * @error: a #GError, or %NULL |
429 | * |
430 | * Finishes ejecting a drive. |
431 | * |
432 | * Returns: %TRUE if the drive has been ejected successfully, |
433 | * %FALSE otherwise. |
434 | * |
435 | * Deprecated: 2.22: Use g_drive_eject_with_operation_finish() instead. |
436 | **/ |
437 | gboolean |
438 | g_drive_eject_finish (GDrive *drive, |
439 | GAsyncResult *result, |
440 | GError **error) |
441 | { |
442 | GDriveIface *iface; |
443 | |
444 | g_return_val_if_fail (G_IS_DRIVE (drive), FALSE); |
445 | g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE); |
446 | |
447 | if (g_async_result_legacy_propagate_error (res: result, error)) |
448 | return FALSE; |
449 | else if (g_async_result_is_tagged (res: result, source_tag: g_drive_eject_with_operation)) |
450 | return g_task_propagate_boolean (G_TASK (result), error); |
451 | |
452 | iface = G_DRIVE_GET_IFACE (drive); |
453 | |
454 | return (* iface->eject_finish) (drive, result, error); |
455 | } |
456 | |
457 | /** |
458 | * g_drive_eject_with_operation: |
459 | * @drive: a #GDrive. |
460 | * @flags: flags affecting the unmount if required for eject |
461 | * @mount_operation: (nullable): a #GMountOperation or %NULL to avoid |
462 | * user interaction. |
463 | * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore. |
464 | * @callback: (nullable): a #GAsyncReadyCallback, or %NULL. |
465 | * @user_data: user data passed to @callback. |
466 | * |
467 | * Ejects a drive. This is an asynchronous operation, and is |
468 | * finished by calling g_drive_eject_with_operation_finish() with the @drive |
469 | * and #GAsyncResult data returned in the @callback. |
470 | * |
471 | * Since: 2.22 |
472 | **/ |
473 | void |
474 | g_drive_eject_with_operation (GDrive *drive, |
475 | GMountUnmountFlags flags, |
476 | GMountOperation *mount_operation, |
477 | GCancellable *cancellable, |
478 | GAsyncReadyCallback callback, |
479 | gpointer user_data) |
480 | { |
481 | GDriveIface *iface; |
482 | |
483 | g_return_if_fail (G_IS_DRIVE (drive)); |
484 | |
485 | iface = G_DRIVE_GET_IFACE (drive); |
486 | |
487 | if (iface->eject == NULL && iface->eject_with_operation == NULL) |
488 | { |
489 | g_task_report_new_error (source_object: drive, callback, callback_data: user_data, |
490 | source_tag: g_drive_eject_with_operation, |
491 | G_IO_ERROR, code: G_IO_ERROR_NOT_SUPPORTED, |
492 | /* Translators: This is an error |
493 | * message for drive objects that |
494 | * don't implement any of eject or eject_with_operation. */ |
495 | _("drive doesn’t implement eject or eject_with_operation" )); |
496 | return; |
497 | } |
498 | |
499 | if (iface->eject_with_operation != NULL) |
500 | (* iface->eject_with_operation) (drive, flags, mount_operation, cancellable, callback, user_data); |
501 | else |
502 | (* iface->eject) (drive, flags, cancellable, callback, user_data); |
503 | } |
504 | |
505 | /** |
506 | * g_drive_eject_with_operation_finish: |
507 | * @drive: a #GDrive. |
508 | * @result: a #GAsyncResult. |
509 | * @error: a #GError location to store the error occurring, or %NULL to |
510 | * ignore. |
511 | * |
512 | * Finishes ejecting a drive. If any errors occurred during the operation, |
513 | * @error will be set to contain the errors and %FALSE will be returned. |
514 | * |
515 | * Returns: %TRUE if the drive was successfully ejected. %FALSE otherwise. |
516 | * |
517 | * Since: 2.22 |
518 | **/ |
519 | gboolean |
520 | g_drive_eject_with_operation_finish (GDrive *drive, |
521 | GAsyncResult *result, |
522 | GError **error) |
523 | { |
524 | GDriveIface *iface; |
525 | |
526 | g_return_val_if_fail (G_IS_DRIVE (drive), FALSE); |
527 | g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE); |
528 | |
529 | if (g_async_result_legacy_propagate_error (res: result, error)) |
530 | return FALSE; |
531 | else if (g_async_result_is_tagged (res: result, source_tag: g_drive_eject_with_operation)) |
532 | return g_task_propagate_boolean (G_TASK (result), error); |
533 | |
534 | iface = G_DRIVE_GET_IFACE (drive); |
535 | if (iface->eject_with_operation_finish != NULL) |
536 | return (* iface->eject_with_operation_finish) (drive, result, error); |
537 | else |
538 | return (* iface->eject_finish) (drive, result, error); |
539 | } |
540 | |
541 | /** |
542 | * g_drive_poll_for_media: |
543 | * @drive: a #GDrive. |
544 | * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore. |
545 | * @callback: (nullable): a #GAsyncReadyCallback, or %NULL. |
546 | * @user_data: user data to pass to @callback |
547 | * |
548 | * Asynchronously polls @drive to see if media has been inserted or removed. |
549 | * |
550 | * When the operation is finished, @callback will be called. |
551 | * You can then call g_drive_poll_for_media_finish() to obtain the |
552 | * result of the operation. |
553 | **/ |
554 | void |
555 | g_drive_poll_for_media (GDrive *drive, |
556 | GCancellable *cancellable, |
557 | GAsyncReadyCallback callback, |
558 | gpointer user_data) |
559 | { |
560 | GDriveIface *iface; |
561 | |
562 | g_return_if_fail (G_IS_DRIVE (drive)); |
563 | |
564 | iface = G_DRIVE_GET_IFACE (drive); |
565 | |
566 | if (iface->poll_for_media == NULL) |
567 | { |
568 | g_task_report_new_error (source_object: drive, callback, callback_data: user_data, |
569 | source_tag: g_drive_poll_for_media, |
570 | G_IO_ERROR, code: G_IO_ERROR_NOT_SUPPORTED, |
571 | _("drive doesn’t implement polling for media" )); |
572 | return; |
573 | } |
574 | |
575 | (* iface->poll_for_media) (drive, cancellable, callback, user_data); |
576 | } |
577 | |
578 | /** |
579 | * g_drive_poll_for_media_finish: |
580 | * @drive: a #GDrive. |
581 | * @result: a #GAsyncResult. |
582 | * @error: a #GError, or %NULL |
583 | * |
584 | * Finishes an operation started with g_drive_poll_for_media() on a drive. |
585 | * |
586 | * Returns: %TRUE if the drive has been poll_for_mediaed successfully, |
587 | * %FALSE otherwise. |
588 | **/ |
589 | gboolean |
590 | g_drive_poll_for_media_finish (GDrive *drive, |
591 | GAsyncResult *result, |
592 | GError **error) |
593 | { |
594 | GDriveIface *iface; |
595 | |
596 | g_return_val_if_fail (G_IS_DRIVE (drive), FALSE); |
597 | g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE); |
598 | |
599 | if (g_async_result_legacy_propagate_error (res: result, error)) |
600 | return FALSE; |
601 | else if (g_async_result_is_tagged (res: result, source_tag: g_drive_poll_for_media)) |
602 | return g_task_propagate_boolean (G_TASK (result), error); |
603 | |
604 | iface = G_DRIVE_GET_IFACE (drive); |
605 | |
606 | return (* iface->poll_for_media_finish) (drive, result, error); |
607 | } |
608 | |
609 | /** |
610 | * g_drive_get_identifier: |
611 | * @drive: a #GDrive |
612 | * @kind: the kind of identifier to return |
613 | * |
614 | * Gets the identifier of the given kind for @drive. The only |
615 | * identifier currently available is |
616 | * #G_DRIVE_IDENTIFIER_KIND_UNIX_DEVICE. |
617 | * |
618 | * Returns: (nullable) (transfer full): a newly allocated string containing the |
619 | * requested identifier, or %NULL if the #GDrive |
620 | * doesn't have this kind of identifier. |
621 | */ |
622 | char * |
623 | g_drive_get_identifier (GDrive *drive, |
624 | const char *kind) |
625 | { |
626 | GDriveIface *iface; |
627 | |
628 | g_return_val_if_fail (G_IS_DRIVE (drive), NULL); |
629 | g_return_val_if_fail (kind != NULL, NULL); |
630 | |
631 | iface = G_DRIVE_GET_IFACE (drive); |
632 | |
633 | if (iface->get_identifier == NULL) |
634 | return NULL; |
635 | |
636 | return (* iface->get_identifier) (drive, kind); |
637 | } |
638 | |
639 | /** |
640 | * g_drive_enumerate_identifiers: |
641 | * @drive: a #GDrive |
642 | * |
643 | * Gets the kinds of identifiers that @drive has. |
644 | * Use g_drive_get_identifier() to obtain the identifiers |
645 | * themselves. |
646 | * |
647 | * Returns: (transfer full) (array zero-terminated=1): a %NULL-terminated |
648 | * array of strings containing kinds of identifiers. Use g_strfreev() |
649 | * to free. |
650 | */ |
651 | char ** |
652 | g_drive_enumerate_identifiers (GDrive *drive) |
653 | { |
654 | GDriveIface *iface; |
655 | |
656 | g_return_val_if_fail (G_IS_DRIVE (drive), NULL); |
657 | iface = G_DRIVE_GET_IFACE (drive); |
658 | |
659 | if (iface->enumerate_identifiers == NULL) |
660 | return NULL; |
661 | |
662 | return (* iface->enumerate_identifiers) (drive); |
663 | } |
664 | |
665 | /** |
666 | * g_drive_get_start_stop_type: |
667 | * @drive: a #GDrive. |
668 | * |
669 | * Gets a hint about how a drive can be started/stopped. |
670 | * |
671 | * Returns: A value from the #GDriveStartStopType enumeration. |
672 | * |
673 | * Since: 2.22 |
674 | */ |
675 | GDriveStartStopType |
676 | g_drive_get_start_stop_type (GDrive *drive) |
677 | { |
678 | GDriveIface *iface; |
679 | |
680 | g_return_val_if_fail (G_IS_DRIVE (drive), FALSE); |
681 | |
682 | iface = G_DRIVE_GET_IFACE (drive); |
683 | |
684 | if (iface->get_start_stop_type == NULL) |
685 | return G_DRIVE_START_STOP_TYPE_UNKNOWN; |
686 | |
687 | return (* iface->get_start_stop_type) (drive); |
688 | } |
689 | |
690 | |
691 | /** |
692 | * g_drive_can_start: |
693 | * @drive: a #GDrive. |
694 | * |
695 | * Checks if a drive can be started. |
696 | * |
697 | * Returns: %TRUE if the @drive can be started, %FALSE otherwise. |
698 | * |
699 | * Since: 2.22 |
700 | */ |
701 | gboolean |
702 | g_drive_can_start (GDrive *drive) |
703 | { |
704 | GDriveIface *iface; |
705 | |
706 | g_return_val_if_fail (G_IS_DRIVE (drive), FALSE); |
707 | |
708 | iface = G_DRIVE_GET_IFACE (drive); |
709 | |
710 | if (iface->can_start == NULL) |
711 | return FALSE; |
712 | |
713 | return (* iface->can_start) (drive); |
714 | } |
715 | |
716 | /** |
717 | * g_drive_can_start_degraded: |
718 | * @drive: a #GDrive. |
719 | * |
720 | * Checks if a drive can be started degraded. |
721 | * |
722 | * Returns: %TRUE if the @drive can be started degraded, %FALSE otherwise. |
723 | * |
724 | * Since: 2.22 |
725 | */ |
726 | gboolean |
727 | g_drive_can_start_degraded (GDrive *drive) |
728 | { |
729 | GDriveIface *iface; |
730 | |
731 | g_return_val_if_fail (G_IS_DRIVE (drive), FALSE); |
732 | |
733 | iface = G_DRIVE_GET_IFACE (drive); |
734 | |
735 | if (iface->can_start_degraded == NULL) |
736 | return FALSE; |
737 | |
738 | return (* iface->can_start_degraded) (drive); |
739 | } |
740 | |
741 | /** |
742 | * g_drive_start: |
743 | * @drive: a #GDrive. |
744 | * @flags: flags affecting the start operation. |
745 | * @mount_operation: (nullable): a #GMountOperation or %NULL to avoid |
746 | * user interaction. |
747 | * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore. |
748 | * @callback: (nullable): a #GAsyncReadyCallback, or %NULL. |
749 | * @user_data: user data to pass to @callback |
750 | * |
751 | * Asynchronously starts a drive. |
752 | * |
753 | * When the operation is finished, @callback will be called. |
754 | * You can then call g_drive_start_finish() to obtain the |
755 | * result of the operation. |
756 | * |
757 | * Since: 2.22 |
758 | */ |
759 | void |
760 | g_drive_start (GDrive *drive, |
761 | GDriveStartFlags flags, |
762 | GMountOperation *mount_operation, |
763 | GCancellable *cancellable, |
764 | GAsyncReadyCallback callback, |
765 | gpointer user_data) |
766 | { |
767 | GDriveIface *iface; |
768 | |
769 | g_return_if_fail (G_IS_DRIVE (drive)); |
770 | |
771 | iface = G_DRIVE_GET_IFACE (drive); |
772 | |
773 | if (iface->start == NULL) |
774 | { |
775 | g_task_report_new_error (source_object: drive, callback, callback_data: user_data, |
776 | source_tag: g_drive_start, |
777 | G_IO_ERROR, code: G_IO_ERROR_NOT_SUPPORTED, |
778 | _("drive doesn’t implement start" )); |
779 | return; |
780 | } |
781 | |
782 | (* iface->start) (drive, flags, mount_operation, cancellable, callback, user_data); |
783 | } |
784 | |
785 | /** |
786 | * g_drive_start_finish: |
787 | * @drive: a #GDrive. |
788 | * @result: a #GAsyncResult. |
789 | * @error: a #GError, or %NULL |
790 | * |
791 | * Finishes starting a drive. |
792 | * |
793 | * Returns: %TRUE if the drive has been started successfully, |
794 | * %FALSE otherwise. |
795 | * |
796 | * Since: 2.22 |
797 | */ |
798 | gboolean |
799 | g_drive_start_finish (GDrive *drive, |
800 | GAsyncResult *result, |
801 | GError **error) |
802 | { |
803 | GDriveIface *iface; |
804 | |
805 | g_return_val_if_fail (G_IS_DRIVE (drive), FALSE); |
806 | g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE); |
807 | |
808 | if (g_async_result_legacy_propagate_error (res: result, error)) |
809 | return FALSE; |
810 | else if (g_async_result_is_tagged (res: result, source_tag: g_drive_start)) |
811 | return g_task_propagate_boolean (G_TASK (result), error); |
812 | |
813 | iface = G_DRIVE_GET_IFACE (drive); |
814 | |
815 | return (* iface->start_finish) (drive, result, error); |
816 | } |
817 | |
818 | /** |
819 | * g_drive_can_stop: |
820 | * @drive: a #GDrive. |
821 | * |
822 | * Checks if a drive can be stopped. |
823 | * |
824 | * Returns: %TRUE if the @drive can be stopped, %FALSE otherwise. |
825 | * |
826 | * Since: 2.22 |
827 | */ |
828 | gboolean |
829 | g_drive_can_stop (GDrive *drive) |
830 | { |
831 | GDriveIface *iface; |
832 | |
833 | g_return_val_if_fail (G_IS_DRIVE (drive), FALSE); |
834 | |
835 | iface = G_DRIVE_GET_IFACE (drive); |
836 | |
837 | if (iface->can_stop == NULL) |
838 | return FALSE; |
839 | |
840 | return (* iface->can_stop) (drive); |
841 | } |
842 | |
843 | /** |
844 | * g_drive_stop: |
845 | * @drive: a #GDrive. |
846 | * @flags: flags affecting the unmount if required for stopping. |
847 | * @mount_operation: (nullable): a #GMountOperation or %NULL to avoid |
848 | * user interaction. |
849 | * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore. |
850 | * @callback: (nullable): a #GAsyncReadyCallback, or %NULL. |
851 | * @user_data: user data to pass to @callback |
852 | * |
853 | * Asynchronously stops a drive. |
854 | * |
855 | * When the operation is finished, @callback will be called. |
856 | * You can then call g_drive_stop_finish() to obtain the |
857 | * result of the operation. |
858 | * |
859 | * Since: 2.22 |
860 | */ |
861 | void |
862 | g_drive_stop (GDrive *drive, |
863 | GMountUnmountFlags flags, |
864 | GMountOperation *mount_operation, |
865 | GCancellable *cancellable, |
866 | GAsyncReadyCallback callback, |
867 | gpointer user_data) |
868 | { |
869 | GDriveIface *iface; |
870 | |
871 | g_return_if_fail (G_IS_DRIVE (drive)); |
872 | |
873 | iface = G_DRIVE_GET_IFACE (drive); |
874 | |
875 | if (iface->stop == NULL) |
876 | { |
877 | g_task_report_new_error (source_object: drive, callback, callback_data: user_data, |
878 | source_tag: g_drive_start, |
879 | G_IO_ERROR, code: G_IO_ERROR_NOT_SUPPORTED, |
880 | _("drive doesn’t implement stop" )); |
881 | return; |
882 | } |
883 | |
884 | (* iface->stop) (drive, flags, mount_operation, cancellable, callback, user_data); |
885 | } |
886 | |
887 | /** |
888 | * g_drive_stop_finish: |
889 | * @drive: a #GDrive. |
890 | * @result: a #GAsyncResult. |
891 | * @error: a #GError, or %NULL |
892 | * |
893 | * Finishes stopping a drive. |
894 | * |
895 | * Returns: %TRUE if the drive has been stopped successfully, |
896 | * %FALSE otherwise. |
897 | * |
898 | * Since: 2.22 |
899 | */ |
900 | gboolean |
901 | g_drive_stop_finish (GDrive *drive, |
902 | GAsyncResult *result, |
903 | GError **error) |
904 | { |
905 | GDriveIface *iface; |
906 | |
907 | g_return_val_if_fail (G_IS_DRIVE (drive), FALSE); |
908 | g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE); |
909 | |
910 | if (g_async_result_legacy_propagate_error (res: result, error)) |
911 | return FALSE; |
912 | else if (g_async_result_is_tagged (res: result, source_tag: g_drive_start)) |
913 | return g_task_propagate_boolean (G_TASK (result), error); |
914 | |
915 | iface = G_DRIVE_GET_IFACE (drive); |
916 | |
917 | return (* iface->stop_finish) (drive, result, error); |
918 | } |
919 | |
920 | /** |
921 | * g_drive_get_sort_key: |
922 | * @drive: A #GDrive. |
923 | * |
924 | * Gets the sort key for @drive, if any. |
925 | * |
926 | * Returns: (nullable): Sorting key for @drive or %NULL if no such key is available. |
927 | * |
928 | * Since: 2.32 |
929 | */ |
930 | const gchar * |
931 | g_drive_get_sort_key (GDrive *drive) |
932 | { |
933 | const gchar *ret = NULL; |
934 | GDriveIface *iface; |
935 | |
936 | g_return_val_if_fail (G_IS_DRIVE (drive), NULL); |
937 | |
938 | iface = G_DRIVE_GET_IFACE (drive); |
939 | if (iface->get_sort_key != NULL) |
940 | ret = iface->get_sort_key (drive); |
941 | |
942 | return ret; |
943 | } |
944 | |