Coverage Report

Created: 2025-06-13 06:55

/src/glib/gio/gdrive.c
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
}