87830233d8d7c2b5218ad6fe31e57ef0c6169b34
[platform/upstream/glib.git] / gio / gvolume.c
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 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 "gmount.h"
24 #include "gvolume.h"
25 #include "gthemedicon.h"
26 #include "gasyncresult.h"
27 #include "gtask.h"
28 #include "gioerror.h"
29 #include "glibintl.h"
30
31
32 /**
33  * SECTION:gvolume
34  * @short_description: Volume management
35  * @include: gio/gio.h
36  * 
37  * The #GVolume interface represents user-visible objects that can be
38  * mounted. Note, when porting from GnomeVFS, #GVolume is the moral
39  * equivalent of #GnomeVFSDrive.
40  *
41  * Mounting a #GVolume instance is an asynchronous operation. For more
42  * information about asynchronous operations, see #GAsyncResult and
43  * #GTask. To mount a #GVolume, first call g_volume_mount() with (at
44  * least) the #GVolume instance, optionally a #GMountOperation object
45  * and a #GAsyncReadyCallback.
46  *
47  * Typically, one will only want to pass %NULL for the
48  * #GMountOperation if automounting all volumes when a desktop session
49  * starts since it's not desirable to put up a lot of dialogs asking
50  * for credentials.
51  *
52  * The callback will be fired when the operation has resolved (either
53  * with success or failure), and a #GAsyncReady structure will be
54  * passed to the callback.  That callback should then call
55  * g_volume_mount_finish() with the #GVolume instance and the
56  * #GAsyncReady data to see if the operation was completed
57  * successfully.  If an @error is present when g_volume_mount_finish()
58  * is called, then it will be filled with any error information.
59  *
60  * <para id="volume-identifier">
61  * It is sometimes necessary to directly access the underlying
62  * operating system object behind a volume (e.g. for passing a volume
63  * to an application via the commandline). For this purpose, GIO
64  * allows to obtain an 'identifier' for the volume. There can be
65  * different kinds of identifiers, such as Hal UDIs, filesystem labels,
66  * traditional Unix devices (e.g. `/dev/sda2`), UUIDs. GIO uses predefined
67  * strings as names for the different kinds of identifiers:
68  * #G_VOLUME_IDENTIFIER_KIND_HAL_UDI, #G_VOLUME_IDENTIFIER_KIND_LABEL, etc.
69  * Use g_volume_get_identifier() to obtain an identifier for a volume.
70  * </para>
71  *
72  * Note that #G_VOLUME_IDENTIFIER_KIND_HAL_UDI will only be available
73  * when the gvfs hal volume monitor is in use. Other volume monitors
74  * will generally be able to provide the #G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE
75  * identifier, which can be used to obtain a hal device by means of
76  * libhal_manager_find_device_string_match().
77  */
78
79 typedef GVolumeIface GVolumeInterface;
80 G_DEFINE_INTERFACE(GVolume, g_volume, G_TYPE_OBJECT)
81
82 static void
83 g_volume_default_init (GVolumeInterface *iface)
84 {
85   /**
86    * GVolume::changed:
87    * 
88    * Emitted when the volume has been changed.
89    */
90   g_signal_new (I_("changed"),
91                 G_TYPE_VOLUME,
92                 G_SIGNAL_RUN_LAST,
93                 G_STRUCT_OFFSET (GVolumeIface, changed),
94                 NULL, NULL,
95                 g_cclosure_marshal_VOID__VOID,
96                 G_TYPE_NONE, 0);
97
98   /**
99    * GVolume::removed:
100    * 
101    * This signal is emitted when the #GVolume have been removed. If
102    * the recipient is holding references to the object they should
103    * release them so the object can be finalized.
104    */
105   g_signal_new (I_("removed"),
106                 G_TYPE_VOLUME,
107                 G_SIGNAL_RUN_LAST,
108                 G_STRUCT_OFFSET (GVolumeIface, removed),
109                 NULL, NULL,
110                 g_cclosure_marshal_VOID__VOID,
111                 G_TYPE_NONE, 0);
112 }
113
114 /**
115  * g_volume_get_name:
116  * @volume: a #GVolume
117  * 
118  * Gets the name of @volume.
119  * 
120  * Returns: the name for the given @volume. The returned string should 
121  *     be freed with g_free() when no longer needed.
122  */
123 char *
124 g_volume_get_name (GVolume *volume)
125 {
126   GVolumeIface *iface;
127
128   g_return_val_if_fail (G_IS_VOLUME (volume), NULL);
129
130   iface = G_VOLUME_GET_IFACE (volume);
131
132   return (* iface->get_name) (volume);
133 }
134
135 /**
136  * g_volume_get_icon:
137  * @volume: a #GVolume
138  * 
139  * Gets the icon for @volume.
140  * 
141  * Returns: (transfer full): a #GIcon.
142  *     The returned object should be unreffed with g_object_unref()
143  *     when no longer needed.
144  */
145 GIcon *
146 g_volume_get_icon (GVolume *volume)
147 {
148   GVolumeIface *iface;
149
150   g_return_val_if_fail (G_IS_VOLUME (volume), NULL);
151
152   iface = G_VOLUME_GET_IFACE (volume);
153
154   return (* iface->get_icon) (volume);
155 }
156
157 /**
158  * g_volume_get_symbolic_icon:
159  * @volume: a #GVolume
160  * 
161  * Gets the symbolic icon for @volume.
162  * 
163  * Returns: (transfer full): a #GIcon.
164  *     The returned object should be unreffed with g_object_unref()
165  *     when no longer needed.
166  *
167  * Since: 2.34
168  */
169 GIcon *
170 g_volume_get_symbolic_icon (GVolume *volume)
171 {
172   GVolumeIface *iface;
173   GIcon *ret;
174
175   g_return_val_if_fail (G_IS_VOLUME (volume), NULL);
176
177   iface = G_VOLUME_GET_IFACE (volume);
178
179   if (iface->get_symbolic_icon != NULL)
180     ret = iface->get_symbolic_icon (volume);
181   else
182     ret = g_themed_icon_new_with_default_fallbacks ("folder-remote-symbolic");
183
184   return ret;
185
186 }
187
188 /**
189  * g_volume_get_uuid:
190  * @volume: a #GVolume
191  * 
192  * Gets the UUID for the @volume. The reference is typically based on
193  * the file system UUID for the volume in question and should be
194  * considered an opaque string. Returns %NULL if there is no UUID
195  * available.
196  * 
197  * Returns: the UUID for @volume or %NULL if no UUID can be computed.
198  *     The returned string should be freed with g_free() 
199  *     when no longer needed.
200  */
201 char *
202 g_volume_get_uuid (GVolume *volume)
203 {
204   GVolumeIface *iface;
205
206   g_return_val_if_fail (G_IS_VOLUME (volume), NULL);
207
208   iface = G_VOLUME_GET_IFACE (volume);
209
210   return (* iface->get_uuid) (volume);
211 }
212   
213 /**
214  * g_volume_get_drive:
215  * @volume: a #GVolume
216  * 
217  * Gets the drive for the @volume.
218  * 
219  * Returns: (transfer full): a #GDrive or %NULL if @volume is not
220  *     associated with a drive. The returned object should be unreffed
221  *     with g_object_unref() when no longer needed.
222  */
223 GDrive *
224 g_volume_get_drive (GVolume *volume)
225 {
226   GVolumeIface *iface;
227
228   g_return_val_if_fail (G_IS_VOLUME (volume), NULL);
229
230   iface = G_VOLUME_GET_IFACE (volume);
231
232   return (* iface->get_drive) (volume);
233 }
234
235 /**
236  * g_volume_get_mount:
237  * @volume: a #GVolume
238  * 
239  * Gets the mount for the @volume.
240  * 
241  * Returns: (transfer full): a #GMount or %NULL if @volume isn't mounted.
242  *     The returned object should be unreffed with g_object_unref()
243  *     when no longer needed.
244  */
245 GMount *
246 g_volume_get_mount (GVolume *volume)
247 {
248   GVolumeIface *iface;
249
250   g_return_val_if_fail (G_IS_VOLUME (volume), NULL);
251
252   iface = G_VOLUME_GET_IFACE (volume);
253
254   return (* iface->get_mount) (volume);
255 }
256
257
258 /**
259  * g_volume_can_mount:
260  * @volume: a #GVolume
261  * 
262  * Checks if a volume can be mounted.
263  * 
264  * Returns: %TRUE if the @volume can be mounted. %FALSE otherwise
265  */
266 gboolean
267 g_volume_can_mount (GVolume *volume)
268 {
269   GVolumeIface *iface;
270
271   g_return_val_if_fail (G_IS_VOLUME (volume), FALSE);
272
273   iface = G_VOLUME_GET_IFACE (volume);
274
275   if (iface->can_mount == NULL)
276     return FALSE;
277
278   return (* iface->can_mount) (volume);
279 }
280
281 /**
282  * g_volume_can_eject:
283  * @volume: a #GVolume
284  * 
285  * Checks if a volume can be ejected.
286  * 
287  * Returns: %TRUE if the @volume can be ejected. %FALSE otherwise
288  */
289 gboolean
290 g_volume_can_eject (GVolume *volume)
291 {
292   GVolumeIface *iface;
293
294   g_return_val_if_fail (G_IS_VOLUME (volume), FALSE);
295
296   iface = G_VOLUME_GET_IFACE (volume);
297
298   if (iface->can_eject == NULL)
299     return FALSE;
300
301   return (* iface->can_eject) (volume);
302 }
303
304 /**
305  * g_volume_should_automount:
306  * @volume: a #GVolume
307  *
308  * Returns whether the volume should be automatically mounted.
309  * 
310  * Returns: %TRUE if the volume should be automatically mounted
311  */
312 gboolean
313 g_volume_should_automount (GVolume *volume)
314 {
315   GVolumeIface *iface;
316
317   g_return_val_if_fail (G_IS_VOLUME (volume), FALSE);
318
319   iface = G_VOLUME_GET_IFACE (volume);
320
321   if (iface->should_automount == NULL)
322     return FALSE;
323
324   return (* iface->should_automount) (volume);
325 }
326
327
328 /**
329  * g_volume_mount:
330  * @volume: a #GVolume
331  * @flags: flags affecting the operation
332  * @mount_operation: (allow-none): a #GMountOperation or %NULL to avoid user interaction
333  * @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore
334  * @callback: (allow-none): a #GAsyncReadyCallback, or %NULL
335  * @user_data: user data that gets passed to @callback
336  * 
337  * Mounts a volume. This is an asynchronous operation, and is
338  * finished by calling g_volume_mount_finish() with the @volume
339  * and #GAsyncResult returned in the @callback.
340  *
341  * Virtual: mount_fn
342  */
343 void
344 g_volume_mount (GVolume             *volume,
345                 GMountMountFlags     flags,
346                 GMountOperation     *mount_operation,
347                 GCancellable        *cancellable,
348                 GAsyncReadyCallback  callback,
349                 gpointer             user_data)
350 {
351   GVolumeIface *iface;
352
353   g_return_if_fail (G_IS_VOLUME (volume));
354
355   iface = G_VOLUME_GET_IFACE (volume);
356
357   if (iface->mount_fn == NULL)
358     {
359       g_task_report_new_error (volume, callback, user_data,
360                                g_volume_mount,
361                                G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
362                                _("volume doesn't implement mount"));
363       return;
364     }
365   
366   (* iface->mount_fn) (volume, flags, mount_operation, cancellable, callback, user_data);
367 }
368
369 /**
370  * g_volume_mount_finish:
371  * @volume: a #GVolume
372  * @result: a #GAsyncResult
373  * @error: a #GError location to store an error, or %NULL to ignore
374  * 
375  * Finishes mounting a volume. If any errors occurred during the operation,
376  * @error will be set to contain the errors and %FALSE will be returned.
377  *
378  * If the mount operation succeeded, g_volume_get_mount() on @volume
379  * is guaranteed to return the mount right after calling this
380  * function; there's no need to listen for the 'mount-added' signal on
381  * #GVolumeMonitor.
382  * 
383  * Returns: %TRUE, %FALSE if operation failed
384  */
385 gboolean
386 g_volume_mount_finish (GVolume       *volume,
387                        GAsyncResult  *result,
388                        GError       **error)
389 {
390   GVolumeIface *iface;
391
392   g_return_val_if_fail (G_IS_VOLUME (volume), FALSE);
393   g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
394
395   if (g_async_result_legacy_propagate_error (result, error))
396     return FALSE;
397   else if (g_async_result_is_tagged (result, g_volume_mount))
398     return g_task_propagate_boolean (G_TASK (result), error);
399   
400   iface = G_VOLUME_GET_IFACE (volume);
401   return (* iface->mount_finish) (volume, result, error);
402 }
403
404 /**
405  * g_volume_eject:
406  * @volume: a #GVolume
407  * @flags: flags affecting the unmount if required for eject
408  * @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore
409  * @callback: (allow-none): a #GAsyncReadyCallback, or %NULL
410  * @user_data: user data that gets passed to @callback
411  * 
412  * Ejects a volume. This is an asynchronous operation, and is
413  * finished by calling g_volume_eject_finish() with the @volume
414  * and #GAsyncResult returned in the @callback.
415  *
416  * Deprecated: 2.22: Use g_volume_eject_with_operation() instead.
417  */
418 void
419 g_volume_eject (GVolume             *volume,
420                 GMountUnmountFlags   flags,
421                 GCancellable        *cancellable,
422                 GAsyncReadyCallback  callback,
423                 gpointer             user_data)
424 {
425   GVolumeIface *iface;
426
427   g_return_if_fail (G_IS_VOLUME (volume));
428
429   iface = G_VOLUME_GET_IFACE (volume);
430
431   if (iface->eject == NULL)
432     {
433       g_task_report_new_error (volume, callback, user_data,
434                                g_volume_eject_with_operation,
435                                G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
436                                _("volume doesn't implement eject"));
437       return;
438     }
439   
440   (* iface->eject) (volume, flags, cancellable, callback, user_data);
441 }
442
443 /**
444  * g_volume_eject_finish:
445  * @volume: pointer to a #GVolume
446  * @result: a #GAsyncResult
447  * @error: a #GError location to store an error, or %NULL to ignore
448  * 
449  * Finishes ejecting a volume. If any errors occurred during the operation,
450  * @error will be set to contain the errors and %FALSE will be returned.
451  * 
452  * Returns: %TRUE, %FALSE if operation failed
453  *
454  * Deprecated: 2.22: Use g_volume_eject_with_operation_finish() instead.
455  **/
456 gboolean
457 g_volume_eject_finish (GVolume       *volume,
458                        GAsyncResult  *result,
459                        GError       **error)
460 {
461   GVolumeIface *iface;
462
463   g_return_val_if_fail (G_IS_VOLUME (volume), FALSE);
464   g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
465
466   if (g_async_result_legacy_propagate_error (result, error))
467     return FALSE;
468   if (g_async_result_is_tagged (result, g_volume_eject_with_operation))
469     return g_task_propagate_boolean (G_TASK (result), error);
470   
471   iface = G_VOLUME_GET_IFACE (volume);
472   return (* iface->eject_finish) (volume, result, error);
473 }
474
475 /**
476  * g_volume_eject_with_operation:
477  * @volume: a #GVolume
478  * @flags: flags affecting the unmount if required for eject
479  * @mount_operation: (allow-none): a #GMountOperation or %NULL to
480  *     avoid user interaction
481  * @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore
482  * @callback: (allow-none): a #GAsyncReadyCallback, or %NULL
483  * @user_data: user data passed to @callback
484  *
485  * Ejects a volume. This is an asynchronous operation, and is
486  * finished by calling g_volume_eject_with_operation_finish() with the @volume
487  * and #GAsyncResult data returned in the @callback.
488  *
489  * Since: 2.22
490  **/
491 void
492 g_volume_eject_with_operation (GVolume              *volume,
493                                GMountUnmountFlags   flags,
494                                GMountOperation     *mount_operation,
495                                GCancellable        *cancellable,
496                                GAsyncReadyCallback  callback,
497                                gpointer             user_data)
498 {
499   GVolumeIface *iface;
500
501   g_return_if_fail (G_IS_VOLUME (volume));
502
503   iface = G_VOLUME_GET_IFACE (volume);
504
505   if (iface->eject == NULL && iface->eject_with_operation == NULL)
506     {
507       g_task_report_new_error (volume, callback, user_data,
508                                g_volume_eject_with_operation,
509                                G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
510                                /* Translators: This is an error
511                                 * message for volume objects that
512                                 * don't implement any of eject or eject_with_operation. */
513                                _("volume doesn't implement eject or eject_with_operation"));
514       return;
515     }
516
517   if (iface->eject_with_operation != NULL)
518     (* iface->eject_with_operation) (volume, flags, mount_operation, cancellable, callback, user_data);
519   else
520     (* iface->eject) (volume, flags, cancellable, callback, user_data);
521 }
522
523 /**
524  * g_volume_eject_with_operation_finish:
525  * @volume: a #GVolume
526  * @result: a #GAsyncResult
527  * @error: a #GError location to store the error occurring, or %NULL
528  *
529  * Finishes ejecting a volume. If any errors occurred during the operation,
530  * @error will be set to contain the errors and %FALSE will be returned.
531  *
532  * Returns: %TRUE if the volume was successfully ejected. %FALSE otherwise
533  *
534  * Since: 2.22
535  **/
536 gboolean
537 g_volume_eject_with_operation_finish (GVolume        *volume,
538                                       GAsyncResult  *result,
539                                       GError       **error)
540 {
541   GVolumeIface *iface;
542
543   g_return_val_if_fail (G_IS_VOLUME (volume), FALSE);
544   g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
545
546   if (g_async_result_legacy_propagate_error (result, error))
547     return FALSE;
548   else if (g_async_result_is_tagged (result, g_volume_eject_with_operation))
549     return g_task_propagate_boolean (G_TASK (result), error);
550
551   iface = G_VOLUME_GET_IFACE (volume);
552   if (iface->eject_with_operation_finish != NULL)
553     return (* iface->eject_with_operation_finish) (volume, result, error);
554   else
555     return (* iface->eject_finish) (volume, result, error);
556 }
557
558 /**
559  * g_volume_get_identifier:
560  * @volume: a #GVolume
561  * @kind: the kind of identifier to return
562  *
563  * Gets the identifier of the given kind for @volume. 
564  * See the <link linkend="volume-identifier">introduction</link>
565  * for more information about volume identifiers.
566  *
567  * Returns: a newly allocated string containing the
568  *     requested identfier, or %NULL if the #GVolume
569  *     doesn't have this kind of identifier
570  */
571 char *
572 g_volume_get_identifier (GVolume    *volume,
573                          const char *kind)
574 {
575   GVolumeIface *iface;
576
577   g_return_val_if_fail (G_IS_VOLUME (volume), NULL);
578   g_return_val_if_fail (kind != NULL, NULL);
579
580   iface = G_VOLUME_GET_IFACE (volume);
581
582   if (iface->get_identifier == NULL)
583     return NULL;
584   
585   return (* iface->get_identifier) (volume, kind);
586 }
587
588 /**
589  * g_volume_enumerate_identifiers:
590  * @volume: a #GVolume
591  * 
592  * Gets the kinds of <link linkend="volume-identifier">identifiers</link>
593  * that @volume has. Use g_volume_get_identifier() to obtain
594  * the identifiers themselves.
595  *
596  * Returns: (array zero-terminated=1) (transfer full): a %NULL-terminated array
597  *   of strings containing kinds of identifiers. Use g_strfreev() to free.
598  */
599 char **
600 g_volume_enumerate_identifiers (GVolume *volume)
601 {
602   GVolumeIface *iface;
603
604   g_return_val_if_fail (G_IS_VOLUME (volume), NULL);
605   iface = G_VOLUME_GET_IFACE (volume);
606
607   if (iface->enumerate_identifiers == NULL)
608     return NULL;
609   
610   return (* iface->enumerate_identifiers) (volume);
611 }
612
613 /**
614  * g_volume_get_activation_root:
615  * @volume: a #GVolume
616  *
617  * Gets the activation root for a #GVolume if it is known ahead of
618  * mount time. Returns %NULL otherwise. If not %NULL and if @volume
619  * is mounted, then the result of g_mount_get_root() on the
620  * #GMount object obtained from g_volume_get_mount() will always
621  * either be equal or a prefix of what this function returns. In
622  * other words, in code
623  *
624  * |[<!-- language="C" -->
625  *   GMount *mount;
626  *   GFile *mount_root
627  *   GFile *volume_activation_root;
628  *
629  *   mount = g_volume_get_mount (volume); /&ast; mounted, so never NULL &ast;/
630  *   mount_root = g_mount_get_root (mount);
631  *   volume_activation_root = g_volume_get_activation_root (volume); /&ast; assume not NULL &ast;/
632  * ]|
633  * then the expression
634  * |[<!-- language="C" -->
635  *   (g_file_has_prefix (volume_activation_root, mount_root) ||
636       g_file_equal (volume_activation_root, mount_root))
637  * ]|
638  * will always be %TRUE.
639  *
640  * Activation roots are typically used in #GVolumeMonitor
641  * implementations to find the underlying mount to shadow, see
642  * g_mount_is_shadowed() for more details.
643  *
644  * Returns: (transfer full): the activation root of @volume or %NULL. Use
645  *     g_object_unref() to free.
646  *
647  * Since: 2.18
648  */
649 GFile *
650 g_volume_get_activation_root (GVolume *volume)
651 {
652   GVolumeIface *iface;
653
654   g_return_val_if_fail (G_IS_VOLUME (volume), NULL);
655   iface = G_VOLUME_GET_IFACE (volume);
656
657   if (iface->get_activation_root == NULL)
658     return NULL;
659
660   return (* iface->get_activation_root) (volume);
661 }
662
663 /**
664  * g_volume_get_sort_key:
665  * @volume: a #GVolume
666  *
667  * Gets the sort key for @volume, if any.
668  *
669  * Returns: Sorting key for @volume or %NULL if no such key is available
670  *
671  * Since: 2.32
672  */
673 const gchar *
674 g_volume_get_sort_key (GVolume *volume)
675 {
676   const gchar *ret = NULL;
677   GVolumeIface *iface;
678
679   g_return_val_if_fail (G_IS_VOLUME (volume), NULL);
680
681   iface = G_VOLUME_GET_IFACE (volume);
682   if (iface->get_sort_key != NULL)
683     ret = iface->get_sort_key (volume);
684
685   return ret;
686 }