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