Coverage Report

Created: 2025-07-01 07:09

/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
 * 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
0
{
70
  /**
71
   * GDrive::changed:
72
   * @drive: a #GDrive.
73
   *
74
   * Emitted when the drive's state has changed.
75
   **/
76
0
  g_signal_new (I_("changed"),
77
0
    G_TYPE_DRIVE,
78
0
    G_SIGNAL_RUN_LAST,
79
0
    G_STRUCT_OFFSET (GDriveIface, changed),
80
0
    NULL, NULL,
81
0
    NULL,
82
0
    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
0
  g_signal_new (I_("disconnected"),
94
0
    G_TYPE_DRIVE,
95
0
    G_SIGNAL_RUN_LAST,
96
0
    G_STRUCT_OFFSET (GDriveIface, disconnected),
97
0
    NULL, NULL,
98
0
    NULL,
99
0
    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
0
  g_signal_new (I_("eject-button"),
109
0
    G_TYPE_DRIVE,
110
0
    G_SIGNAL_RUN_LAST,
111
0
    G_STRUCT_OFFSET (GDriveIface, eject_button),
112
0
    NULL, NULL,
113
0
    NULL,
114
0
    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
0
  g_signal_new (I_("stop-button"),
126
0
    G_TYPE_DRIVE,
127
0
    G_SIGNAL_RUN_LAST,
128
0
    G_STRUCT_OFFSET (GDriveIface, stop_button),
129
0
    NULL, NULL,
130
0
    NULL,
131
0
    G_TYPE_NONE, 0);
132
0
}
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
0
{
146
0
  GDriveIface *iface;
147
148
0
  g_return_val_if_fail (G_IS_DRIVE (drive), NULL);
149
150
0
  iface = G_DRIVE_GET_IFACE (drive);
151
152
0
  return (* iface->get_name) (drive);
153
0
}
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
0
{
167
0
  GDriveIface *iface;
168
  
169
0
  g_return_val_if_fail (G_IS_DRIVE (drive), NULL);
170
171
0
  iface = G_DRIVE_GET_IFACE (drive);
172
173
0
  return (* iface->get_icon) (drive);
174
0
}
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
0
{
190
0
  GDriveIface *iface;
191
0
  GIcon *ret;
192
193
0
  g_return_val_if_fail (G_IS_DRIVE (drive), NULL);
194
195
0
  iface = G_DRIVE_GET_IFACE (drive);
196
197
0
  if (iface->get_symbolic_icon != NULL)
198
0
    ret = iface->get_symbolic_icon (drive);
199
0
  else
200
0
    ret = g_themed_icon_new_with_default_fallbacks ("drive-removable-media-symbolic");
201
202
0
  return ret;
203
0
}
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
0
{
216
0
  GDriveIface *iface;
217
218
0
  g_return_val_if_fail (G_IS_DRIVE (drive), FALSE);
219
220
0
  iface = G_DRIVE_GET_IFACE (drive);
221
222
0
  return (* iface->has_volumes) (drive);
223
0
}
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
0
{
239
0
  GDriveIface *iface;
240
241
0
  g_return_val_if_fail (G_IS_DRIVE (drive), NULL);
242
243
0
  iface = G_DRIVE_GET_IFACE (drive);
244
245
0
  return (* iface->get_volumes) (drive);
246
0
}
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
0
{
260
0
  GDriveIface *iface;
261
262
0
  g_return_val_if_fail (G_IS_DRIVE (drive), FALSE);
263
264
0
  iface = G_DRIVE_GET_IFACE (drive);
265
266
0
  return (* iface->is_media_check_automatic) (drive);
267
0
}
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
0
{
283
0
  GDriveIface *iface;
284
285
0
  g_return_val_if_fail (G_IS_DRIVE (drive), FALSE);
286
287
0
  iface = G_DRIVE_GET_IFACE (drive);
288
0
  if (iface->is_removable != NULL)
289
0
    return iface->is_removable (drive);
290
291
0
  return FALSE;
292
0
}
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
0
{
305
0
  GDriveIface *iface;
306
307
0
  g_return_val_if_fail (G_IS_DRIVE (drive), FALSE);
308
309
0
  iface = G_DRIVE_GET_IFACE (drive);
310
311
0
  return (* iface->is_media_removable) (drive);
312
0
}
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
0
{
327
0
  GDriveIface *iface;
328
329
0
  g_return_val_if_fail (G_IS_DRIVE (drive), FALSE);
330
331
0
  iface = G_DRIVE_GET_IFACE (drive);
332
333
0
  return (* iface->has_media) (drive);
334
0
}
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
0
{
347
0
  GDriveIface *iface;
348
349
0
  g_return_val_if_fail (G_IS_DRIVE (drive), FALSE);
350
351
0
  iface = G_DRIVE_GET_IFACE (drive);
352
353
0
  if (iface->can_eject == NULL)
354
0
    return FALSE;
355
356
0
  return (* iface->can_eject) (drive);
357
0
}
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
0
{
371
0
  GDriveIface *iface;
372
373
0
  g_return_val_if_fail (G_IS_DRIVE (drive), FALSE);
374
375
0
  iface = G_DRIVE_GET_IFACE (drive);
376
377
0
  if (iface->poll_for_media == NULL)
378
0
    return FALSE;
379
380
0
  return (* iface->can_poll_for_media) (drive);
381
0
}
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
0
{
406
0
  GDriveIface *iface;
407
408
0
  g_return_if_fail (G_IS_DRIVE (drive));
409
410
0
  iface = G_DRIVE_GET_IFACE (drive);
411
412
0
  if (iface->eject == NULL)
413
0
    {
414
0
      g_task_report_new_error (drive, callback, user_data,
415
0
                               g_drive_eject_with_operation,
416
0
                               G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
417
0
                               _("drive doesn’t implement eject"));
418
0
      return;
419
0
    }
420
  
421
0
  (* iface->eject) (drive, flags, cancellable, callback, user_data);
422
0
}
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
0
{
442
0
  GDriveIface *iface;
443
444
0
  g_return_val_if_fail (G_IS_DRIVE (drive), FALSE);
445
0
  g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
446
447
0
  if (g_async_result_legacy_propagate_error (result, error))
448
0
    return FALSE;
449
0
  else if (g_async_result_is_tagged (result, g_drive_eject_with_operation))
450
0
    return g_task_propagate_boolean (G_TASK (result), error);
451
452
0
  iface = G_DRIVE_GET_IFACE (drive);
453
  
454
0
  return (* iface->eject_finish) (drive, result, error);
455
0
}
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
0
{
481
0
  GDriveIface *iface;
482
483
0
  g_return_if_fail (G_IS_DRIVE (drive));
484
485
0
  iface = G_DRIVE_GET_IFACE (drive);
486
487
0
  if (iface->eject == NULL && iface->eject_with_operation == NULL)
488
0
    {
489
0
      g_task_report_new_error (drive, callback, user_data,
490
0
                               g_drive_eject_with_operation,
491
0
                               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
0
                               _("drive doesn’t implement eject or eject_with_operation"));
496
0
      return;
497
0
    }
498
499
0
  if (iface->eject_with_operation != NULL)
500
0
    (* iface->eject_with_operation) (drive, flags, mount_operation, cancellable, callback, user_data);
501
0
  else
502
0
    (* iface->eject) (drive, flags, cancellable, callback, user_data);
503
0
}
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
0
{
524
0
  GDriveIface *iface;
525
526
0
  g_return_val_if_fail (G_IS_DRIVE (drive), FALSE);
527
0
  g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
528
529
0
  if (g_async_result_legacy_propagate_error (result, error))
530
0
    return FALSE;
531
0
  else if (g_async_result_is_tagged (result, g_drive_eject_with_operation))
532
0
    return g_task_propagate_boolean (G_TASK (result), error);
533
534
0
  iface = G_DRIVE_GET_IFACE (drive);
535
0
  if (iface->eject_with_operation_finish != NULL)
536
0
    return (* iface->eject_with_operation_finish) (drive, result, error);
537
0
  else
538
0
    return (* iface->eject_finish) (drive, result, error);
539
0
}
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
0
{
560
0
  GDriveIface *iface;
561
562
0
  g_return_if_fail (G_IS_DRIVE (drive));
563
564
0
  iface = G_DRIVE_GET_IFACE (drive);
565
566
0
  if (iface->poll_for_media == NULL)
567
0
    {
568
0
      g_task_report_new_error (drive, callback, user_data,
569
0
                               g_drive_poll_for_media,
570
0
                               G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
571
0
                               _("drive doesn’t implement polling for media"));
572
0
      return;
573
0
    }
574
  
575
0
  (* iface->poll_for_media) (drive, cancellable, callback, user_data);
576
0
}
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
0
{
594
0
  GDriveIface *iface;
595
596
0
  g_return_val_if_fail (G_IS_DRIVE (drive), FALSE);
597
0
  g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
598
599
0
  if (g_async_result_legacy_propagate_error (result, error))
600
0
    return FALSE;
601
0
  else if (g_async_result_is_tagged (result, g_drive_poll_for_media))
602
0
    return g_task_propagate_boolean (G_TASK (result), error);
603
604
0
  iface = G_DRIVE_GET_IFACE (drive);
605
  
606
0
  return (* iface->poll_for_media_finish) (drive, result, error);
607
0
}
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
0
{
626
0
  GDriveIface *iface;
627
628
0
  g_return_val_if_fail (G_IS_DRIVE (drive), NULL);
629
0
  g_return_val_if_fail (kind != NULL, NULL);
630
631
0
  iface = G_DRIVE_GET_IFACE (drive);
632
633
0
  if (iface->get_identifier == NULL)
634
0
    return NULL;
635
  
636
0
  return (* iface->get_identifier) (drive, kind);
637
0
}
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
0
{
654
0
  GDriveIface *iface;
655
656
0
  g_return_val_if_fail (G_IS_DRIVE (drive), NULL);
657
0
  iface = G_DRIVE_GET_IFACE (drive);
658
659
0
  if (iface->enumerate_identifiers == NULL)
660
0
    return NULL;
661
  
662
0
  return (* iface->enumerate_identifiers) (drive);
663
0
}
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
0
{
678
0
  GDriveIface *iface;
679
680
0
  g_return_val_if_fail (G_IS_DRIVE (drive), FALSE);
681
682
0
  iface = G_DRIVE_GET_IFACE (drive);
683
684
0
  if (iface->get_start_stop_type == NULL)
685
0
    return G_DRIVE_START_STOP_TYPE_UNKNOWN;
686
687
0
  return (* iface->get_start_stop_type) (drive);
688
0
}
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
0
{
704
0
  GDriveIface *iface;
705
706
0
  g_return_val_if_fail (G_IS_DRIVE (drive), FALSE);
707
708
0
  iface = G_DRIVE_GET_IFACE (drive);
709
710
0
  if (iface->can_start == NULL)
711
0
    return FALSE;
712
713
0
  return (* iface->can_start) (drive);
714
0
}
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
0
{
729
0
  GDriveIface *iface;
730
731
0
  g_return_val_if_fail (G_IS_DRIVE (drive), FALSE);
732
733
0
  iface = G_DRIVE_GET_IFACE (drive);
734
735
0
  if (iface->can_start_degraded == NULL)
736
0
    return FALSE;
737
738
0
  return (* iface->can_start_degraded) (drive);
739
0
}
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
0
{
767
0
  GDriveIface *iface;
768
769
0
  g_return_if_fail (G_IS_DRIVE (drive));
770
771
0
  iface = G_DRIVE_GET_IFACE (drive);
772
773
0
  if (iface->start == NULL)
774
0
    {
775
0
      g_task_report_new_error (drive, callback, user_data,
776
0
                               g_drive_start,
777
0
                               G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
778
0
                               _("drive doesn’t implement start"));
779
0
      return;
780
0
    }
781
782
0
  (* iface->start) (drive, flags, mount_operation, cancellable, callback, user_data);
783
0
}
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
0
{
803
0
  GDriveIface *iface;
804
805
0
  g_return_val_if_fail (G_IS_DRIVE (drive), FALSE);
806
0
  g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
807
808
0
  if (g_async_result_legacy_propagate_error (result, error))
809
0
    return FALSE;
810
0
  else if (g_async_result_is_tagged (result, g_drive_start))
811
0
    return g_task_propagate_boolean (G_TASK (result), error);
812
813
0
  iface = G_DRIVE_GET_IFACE (drive);
814
815
0
  return (* iface->start_finish) (drive, result, error);
816
0
}
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
0
{
831
0
  GDriveIface *iface;
832
833
0
  g_return_val_if_fail (G_IS_DRIVE (drive), FALSE);
834
835
0
  iface = G_DRIVE_GET_IFACE (drive);
836
837
0
  if (iface->can_stop == NULL)
838
0
    return FALSE;
839
840
0
  return (* iface->can_stop) (drive);
841
0
}
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
0
{
869
0
  GDriveIface *iface;
870
871
0
  g_return_if_fail (G_IS_DRIVE (drive));
872
873
0
  iface = G_DRIVE_GET_IFACE (drive);
874
875
0
  if (iface->stop == NULL)
876
0
    {
877
0
      g_task_report_new_error (drive, callback, user_data,
878
0
                               g_drive_start,
879
0
                               G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
880
0
                               _("drive doesn’t implement stop"));
881
0
      return;
882
0
    }
883
884
0
  (* iface->stop) (drive, flags, mount_operation, cancellable, callback, user_data);
885
0
}
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
0
{
905
0
  GDriveIface *iface;
906
907
0
  g_return_val_if_fail (G_IS_DRIVE (drive), FALSE);
908
0
  g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
909
910
0
  if (g_async_result_legacy_propagate_error (result, error))
911
0
    return FALSE;
912
0
  else if (g_async_result_is_tagged (result, g_drive_start))
913
0
    return g_task_propagate_boolean (G_TASK (result), error);
914
915
0
  iface = G_DRIVE_GET_IFACE (drive);
916
917
0
  return (* iface->stop_finish) (drive, result, error);
918
0
}
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
0
{
933
0
  const gchar *ret = NULL;
934
0
  GDriveIface *iface;
935
936
0
  g_return_val_if_fail (G_IS_DRIVE (drive), NULL);
937
938
0
  iface = G_DRIVE_GET_IFACE (drive);
939
0
  if (iface->get_sort_key != NULL)
940
0
    ret = iface->get_sort_key (drive);
941
942
0
  return ret;
943
0
}