diff --git a/gio/ChangeLog b/gio/ChangeLog index e37d57530..f19525230 100644 --- a/gio/ChangeLog +++ b/gio/ChangeLog @@ -1,3 +1,88 @@ +2007-12-11 David Zeuthen + + Rework how volumes, drives and volume monitoring is + done. Previosly the model was + + GDrive <1-1> GVolume + + where a GDrive instance represented a mount point and a GVolume + instance represented a mounted file system. This patch changes it + the model to + + GDrive <1-N> GVolume <1-1> GMount + + where GMount now serves the purpose of the old GVolume and the new + GVolume serves the purpose of the old GDrive. In addition the new + GDrive interface is used to represent a collection of GVolume + instances (typically partitions) and also contains utility to query + the state of the physical drive the GDrive object represents (such + as checking for media, polling the drive, ejecting the media etc.). + + Also implement mounting and unmounting in the Unix volume monitor + backend. A subquent patch will introduce GDrive support for ejection + of media. + + * Makefile.am: + * gdrive.c: (g_drive_is_media_check_automatic), + (g_drive_is_media_removable), (g_drive_has_media), + (g_drive_can_poll_for_media), (g_drive_eject), + (g_drive_eject_finish), (g_drive_poll_for_media), + (g_drive_poll_for_media_finish): + * gdrive.h: + * gfile.c: (g_file_find_enclosing_mount): + * gfile.h: + * gio.symbols: + * glocaldirectorymonitor.c: + (g_local_directory_monitor_constructor), (mounts_changed): + * glocalfile.c: (get_mount_info), + (g_local_file_find_enclosing_mount), + (g_local_file_file_iface_init): + * gnativevolumemonitor.h: + * gunionvolumemonitor.c: (get_mounts), (get_volumes), + (get_connected_drives), (g_union_volume_monitor_class_init), + (child_volume_added), (child_volume_removed), + (child_volume_changed), (child_mount_added), (child_mount_removed), + (child_mount_pre_unmount), (child_mount_changed), + (child_drive_changed), (g_union_volume_monitor_add_monitor), + (g_union_volume_monitor_remove_monitor), + (_g_mount_get_for_mount_path): + * gunixmounts.c: (g_unix_is_mount_path_system_internal), + (guess_system_internal), (_g_get_unix_mounts), + (_g_get_unix_mount_points), (g_get_unix_mount_at), + (g_unix_mount_free), (g_unix_mount_compare), + (g_unix_mount_get_mount_path), (g_unix_mount_get_device_path), + (g_unix_mount_get_fs_type), (g_unix_mount_is_readonly), + (g_unix_mount_is_system_internal), (g_unix_mount_guess_type), + (type_to_icon), (g_unix_mount_guess_name), + (g_unix_mount_guess_icon), (g_unix_mount_point_guess_name), + (g_unix_mount_point_guess_icon), (_canonicalize_filename), + (_resolve_symlink), (_resolve_dev_root): + * gunixmounts.h: + * gunixvolume.c: (g_unix_volume_finalize), (_g_unix_volume_new), + (_g_unix_volume_disconnected), (_g_unix_volume_set_mount), + (_g_unix_volume_unset_mount), (g_unix_volume_get_icon), + (g_unix_volume_get_name), (g_unix_volume_can_mount), + (g_unix_volume_get_drive), (g_unix_volume_get_mount), + (_g_unix_volume_has_mount_path), (mount_cb), (mount_read_error), + (g_unix_volume_mount), (g_unix_volume_mount_finish), + (g_unix_volume_volume_iface_init): + * gunixvolume.h: + * gunixvolumemonitor.c: (g_unix_volume_monitor_finalize), + (get_mounts), (get_volumes), (get_connected_drives), + (get_mount_for_mount_path), (g_unix_volume_monitor_class_init), + (mountpoints_changed), (mounts_changed), + (g_unix_volume_monitor_init), + (_g_unix_volume_monitor_lookup_volume_for_mount_path), + (find_mount_by_mountpath), (update_volumes), (update_mounts): + * gunixvolumemonitor.h: + * gvolume.c: (g_volume_get_mount), (g_volume_can_mount), + (g_volume_mount), (g_volume_mount_finish): + * gvolume.h: + * gvolumemonitor.c: (g_volume_monitor_class_init), + (g_volume_monitor_get_connected_drives), + (g_volume_monitor_get_volumes), (g_volume_monitor_get_mounts): + * gvolumemonitor.h: + 2007-12-10 Matthias Clasen * gmountoperation.h (GPasswordFlags): Close the gap diff --git a/gio/Makefile.am b/gio/Makefile.am index 3516aaf15..07c9e8c27 100644 --- a/gio/Makefile.am +++ b/gio/Makefile.am @@ -90,8 +90,8 @@ if OS_UNIX appinfo_sources += gdesktopappinfo.c gdesktopappinfo.h platform_libadd += xdgmime/libxdgmime.la unix_sources = \ - gunixdrive.c \ - gunixdrive.h \ + gunixmount.c \ + gunixmount.h \ gunixmounts.c \ gunixmounts.h \ gunixvolume.c \ @@ -102,6 +102,7 @@ unix_sources = \ gunixoutputstream.c \ $(NULL) + giounixincludedir=$(includedir)/gio-unix-2.0/gio giounixinclude_HEADERS = \ gdesktopappinfo.h \ @@ -150,6 +151,7 @@ libgio_2_0_la_SOURCES = \ giomodule-priv.h \ gioscheduler.c \ gloadableicon.c \ + gmount.c \ gmemoryinputstream.c \ gmemoryoutputstream.c \ gmountoperation.c \ @@ -166,7 +168,7 @@ libgio_2_0_la_SOURCES = \ gvfs.c \ gvolume.c \ gvolumemonitor.c \ - gvolumeprivate.h \ + gmountprivate.h \ gioenumtypes.h \ gioenumtypes.c \ $(appinfo_sources) \ @@ -222,6 +224,7 @@ gio_headers = \ giomodule.h \ gioscheduler.h \ gloadableicon.h \ + gmount.h \ gmemoryinputstream.h \ gmemoryoutputstream.h \ gmountoperation.h \ diff --git a/gio/gdrive.c b/gio/gdrive.c index 41e5171a6..06d90979e 100644 --- a/gio/gdrive.c +++ b/gio/gdrive.c @@ -18,6 +18,7 @@ * Boston, MA 02111-1307, USA. * * Author: Alexander Larsson + * David Zeuthen */ #include @@ -32,9 +33,19 @@ * @short_description: Virtual File System drive management * @include: gio/gdrive.h * - * #GDrive manages drive operations from GVFS, including volume mounting - * and ejecting, and getting the drive's name and icon. - * + * #GDrive is a container class for #GVolume objects that stem from + * the same piece of media. As such, #GDrive abstracts a drive with + * (or without) removable media and provides operations for querying + * whether media is available, determing whether media change is + * automatically detected and ejecting the media. + * + * If the #GDrive reports that media isn't automatically detected, one + * can poll for media; typically one should not do this periodically + * as a poll for media operation is potententially expensive and may + * spin up the drive creating noise. + * + * For porting from GnomeVFS note that there is no equivalent of + * #GDrive in that API. **/ static void g_drive_base_init (gpointer g_class); @@ -148,9 +159,9 @@ g_drive_get_icon (GDrive *drive) * g_drive_has_volumes: * @drive: a #GDrive. * - * Checks if a drive has any volumes. + * Check if @drive has any mountable volumes. * - * Returns: %TRUE if @drive contains volumes, %FALSE otherwise. + * Returns: %TRUE if the @drive contains volumes, %FALSE otherwise. **/ gboolean g_drive_has_volumes (GDrive *drive) @@ -168,10 +179,9 @@ g_drive_has_volumes (GDrive *drive) * g_drive_get_volumes: * @drive: a #GDrive. * - * Gets a list of volumes for a drive. + * Get a list of mountable volumes for @drive. * * Returns: #GList containing any #GVolumes on the given @drive. - * **/ GList * g_drive_get_volumes (GDrive *drive) @@ -186,15 +196,15 @@ g_drive_get_volumes (GDrive *drive) } /** - * g_drive_is_automounted: + * g_drive_is_media_check_automatic: * @drive: a #GDrive. * - * Checks if a drive was automatically mounted, e.g. by HAL. + * Checks if @drive is capabable of automatically detecting media changes. * - * Returns: %TRUE if the drive was automounted. %FALSE otherwise. + * Returns: %TRUE if the @drive is capabable of automatically detecting media changes, %FALSE otherwise. **/ gboolean -g_drive_is_automounted (GDrive *drive) +g_drive_is_media_check_automatic (GDrive *drive) { GDriveIface *iface; @@ -202,19 +212,19 @@ g_drive_is_automounted (GDrive *drive) iface = G_DRIVE_GET_IFACE (drive); - return (* iface->is_automounted) (drive); + return (* iface->is_media_check_automatic) (drive); } /** - * g_drive_can_mount: + * g_drive_is_media_removable: * @drive: a #GDrive. * - * Checks if a drive can be mounted. + * Checks if the @drive supports removable media. * - * Returns: %TRUE if the @drive can be mounted. %FALSE otherwise. + * Returns: %TRUE if @drive supports removable media, %FALSE otherwise. **/ gboolean -g_drive_can_mount (GDrive *drive) +g_drive_is_media_removable (GDrive *drive) { GDriveIface *iface; @@ -222,10 +232,29 @@ g_drive_can_mount (GDrive *drive) iface = G_DRIVE_GET_IFACE (drive); - if (iface->can_mount == NULL) - return FALSE; + return (* iface->is_media_removable) (drive); +} - return (* iface->can_mount) (drive); +/** + * g_drive_has_media: + * @drive: a #GDrive. + * + * Checks if the @drive has media. Note that the OS may not be polling + * the drive for media changes; see g_drive_is_media_check_automatic() + * for more details. + * + * Returns: %TRUE if @drive has media, %FALSE otherwise. + **/ +gboolean +g_drive_has_media (GDrive *drive) +{ + GDriveIface *iface; + + g_return_val_if_fail (G_IS_DRIVE (drive), FALSE); + + iface = G_DRIVE_GET_IFACE (drive); + + return (* iface->has_media) (drive); } /** @@ -252,74 +281,26 @@ g_drive_can_eject (GDrive *drive) } /** - * g_drive_mount: + * g_drive_can_poll_for_media: * @drive: a #GDrive. - * @mount_operation: a #GMountOperation. - * @cancellable: optional #GCancellable object, %NULL to ignore. - * @callback: a #GAsyncReadyCallback. - * @user_data: a #gpointer. * - * Mounts a drive. - **/ -void -g_drive_mount (GDrive *drive, - GMountOperation *mount_operation, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GDriveIface *iface; - - g_return_if_fail (G_IS_DRIVE (drive)); - g_return_if_fail (G_IS_MOUNT_OPERATION (mount_operation)); - - iface = G_DRIVE_GET_IFACE (drive); - - if (iface->mount_fn == NULL) - { - g_simple_async_report_error_in_idle (G_OBJECT (drive), callback, user_data, - G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, - _("drive doesn't implement mount")); - - return; - } - - (* iface->mount_fn) (drive, mount_operation, cancellable, callback, user_data); -} - -/** - * g_drive_mount_finish: - * @drive: a #GDrive. - * @result: a #GAsyncResult. - * @error: a #GError. + * Checks if a drive can be polled for media changes. * - * Finishes mounting a drive. - * - * If the @drive's interface does not implement the mount operation, @error will - * be set to %G_IO_ERROR_NOT_SUPPORTED and %FALSE will be returned. - * - * Returns: %TRUE if the mount was finished successfully, - * %FALSE if operation failed. + * Returns: %TRUE if the @drive can be polled for media changes. %FALSE otherwise. **/ gboolean -g_drive_mount_finish (GDrive *drive, - GAsyncResult *result, - GError **error) +g_drive_can_poll_for_media (GDrive *drive) { GDriveIface *iface; g_return_val_if_fail (G_IS_DRIVE (drive), FALSE); - g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE); - if (G_IS_SIMPLE_ASYNC_RESULT (result)) - { - GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result); - if (g_simple_async_result_propagate_error (simple, error)) - return FALSE; - } - iface = G_DRIVE_GET_IFACE (drive); - return (* iface->mount_finish) (drive, result, error); + + if (iface->poll_for_media == NULL) + return FALSE; + + return (* iface->can_poll_for_media) (drive); } /** @@ -363,9 +344,6 @@ g_drive_eject (GDrive *drive, * @error: a #GError. * * Finishes ejecting a drive. - * - * If @drive's interface does not implement the eject operation, @error will - * be set to %G_IO_ERROR_NOT_SUPPORTED and %FALSE will be returned. * * Returns: %TRUE if the drive has been ejected successfully, * %FALSE otherwise. @@ -389,7 +367,74 @@ g_drive_eject_finish (GDrive *drive, iface = G_DRIVE_GET_IFACE (drive); - return (* iface->mount_finish) (drive, result, error); + return (* iface->eject_finish) (drive, result, error); +} + +/** + * g_drive_poll_for_media: + * @drive: a #GDrive. + * @cancellable: optional #GCancellable object, %NULL to ignore. + * @callback: a #GAsyncReadyCallback. + * @user_data: a #gpointer. + * + * Polls @drive to see if media has been inserted or removed. + * + **/ +void +g_drive_poll_for_media (GDrive *drive, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GDriveIface *iface; + + g_return_if_fail (G_IS_DRIVE (drive)); + + iface = G_DRIVE_GET_IFACE (drive); + + if (iface->poll_for_media == NULL) + { + g_simple_async_report_error_in_idle (G_OBJECT (drive), callback, user_data, + G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + _("drive doesn't implement polling for media")); + + return; + } + + (* iface->poll_for_media) (drive, cancellable, callback, user_data); +} + +/** + * g_drive_poll_for_media_finish + * @drive: a #GDrive. + * @result: a #GAsyncResult. + * @error: a #GError. + * + * Finishes poll_for_mediaing a drive. + * + * Returns: %TRUE if the drive has been poll_for_mediaed successfully, + * %FALSE otherwise. + **/ +gboolean +g_drive_poll_for_media_finish (GDrive *drive, + GAsyncResult *result, + GError **error) +{ + GDriveIface *iface; + + g_return_val_if_fail (G_IS_DRIVE (drive), FALSE); + g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE); + + if (G_IS_SIMPLE_ASYNC_RESULT (result)) + { + GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result); + if (g_simple_async_result_propagate_error (simple, error)) + return FALSE; + } + + iface = G_DRIVE_GET_IFACE (drive); + + return (* iface->poll_for_media_finish) (drive, result, error); } #define __G_DRIVE_C__ diff --git a/gio/gdrive.h b/gio/gdrive.h index f81339c8c..53de2300b 100644 --- a/gio/gdrive.h +++ b/gio/gdrive.h @@ -18,12 +18,14 @@ * Boston, MA 02111-1307, USA. * * Author: Alexander Larsson + * David Zeuthen */ #ifndef __G_DRIVE_H__ #define __G_DRIVE_H__ #include +#include #include #include @@ -41,14 +43,16 @@ G_BEGIN_DECLS * @get_name: Returns the name for the given #GDrive. * @get_icon: Returns a #GIcon for the given #GDrive. * @has_volumes: Returns %TRUE if the #GDrive has mountable volumes. - * @get_volumes: Returns a #GList of volumes for the #GDrive. - * @is_automounted: returns %TRUE if the #GDrive was automounted. - * @can_mount: Returns %TRUE if the #GDrive can be mounted. - * @can_eject: Returns %TRUE if the #GDrive can be ejected. - * @mount_fn: Mounts a given #GDrive. - * @mount_finish: Finishes a mount operation. + * @get_volumes: Returns a list #GList of #GVolume for the #GDrive. + * @is_media_removable: Returns %TRUE if the #GDrive supports removal and insertion of media. + * @has_media: Returns %TRUE if the #GDrive has media inserted. + * @is_media_check_automatic: Returns %TRUE if the #GDrive is capabable of automatically detecting media changes. + * @can_poll_for_media: Returns %TRUE if the #GDrive is capable of manually polling for media change. + * @can_eject: Returns %TRUE if the #GDrive can eject media. * @eject: Ejects a #GDrive. * @eject_finish: Finishes an eject operation. + * @poll_for_media: Poll for media insertion/removal on a #GDrive. + * @poll_for_media_finish: Finishes a media poll operation. * * Interface for creating #GDrive implementations. */ @@ -59,58 +63,70 @@ struct _GDriveIface GTypeInterface g_iface; /* signals */ - void (*changed) (GVolume *volume); + void (*changed) (GDrive *drive); /* Virtual Table */ - - char * (*get_name) (GDrive *drive); - GIcon * (*get_icon) (GDrive *drive); - gboolean (*has_volumes) (GDrive *drive); - GList * (*get_volumes) (GDrive *drive); - gboolean (*is_automounted)(GDrive *drive); - gboolean (*can_mount) (GDrive *drive); - gboolean (*can_eject) (GDrive *drive); - void (*mount_fn) (GDrive *drive, - GMountOperation *mount_operation, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - gboolean (*mount_finish)(GDrive *drive, - GAsyncResult *result, - GError **error); - void (*eject) (GDrive *drive, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - gboolean (*eject_finish)(GDrive *drive, - GAsyncResult *result, - GError **error); + char * (*get_name) (GDrive *drive); + GIcon * (*get_icon) (GDrive *drive); + gboolean (*has_volumes) (GDrive *drive); + GList * (*get_volumes) (GDrive *drive); + gboolean (*is_media_removable) (GDrive *drive); + gboolean (*has_media) (GDrive *drive); + gboolean (*is_media_check_automatic) (GDrive *drive); + gboolean (*can_eject) (GDrive *drive); + gboolean (*can_poll_for_media) (GDrive *drive); + void (*eject) (GDrive *drive, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + gboolean (*eject_finish) (GDrive *drive, + GAsyncResult *result, + GError **error); + void (*poll_for_media) (GDrive *drive, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + gboolean (*poll_for_media_finish) (GDrive *drive, + GAsyncResult *result, + GError **error); + + /*< private >*/ + /* Padding for future expansion */ + void (*_g_reserved1) (void); + void (*_g_reserved2) (void); + void (*_g_reserved3) (void); + void (*_g_reserved4) (void); + void (*_g_reserved5) (void); + void (*_g_reserved6) (void); + void (*_g_reserved7) (void); + void (*_g_reserved8) (void); }; -GType g_drive_get_type (void) G_GNUC_CONST; +GType g_drive_get_type (void) G_GNUC_CONST; -char * g_drive_get_name (GDrive *drive); -GIcon * g_drive_get_icon (GDrive *drive); -gboolean g_drive_has_volumes (GDrive *drive); -GList * g_drive_get_volumes (GDrive *drive); -gboolean g_drive_is_automounted (GDrive *drive); -gboolean g_drive_can_mount (GDrive *drive); -gboolean g_drive_can_eject (GDrive *drive); -void g_drive_mount (GDrive *drive, - GMountOperation *mount_operation, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); -gboolean g_drive_mount_finish (GDrive *drive, - GAsyncResult *result, - GError **error); -void g_drive_eject (GDrive *drive, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); -gboolean g_drive_eject_finish (GDrive *drive, - GAsyncResult *result, - GError **error); +char * g_drive_get_name (GDrive *drive); +GIcon * g_drive_get_icon (GDrive *drive); +gboolean g_drive_has_volumes (GDrive *drive); +GList * g_drive_get_volumes (GDrive *drive); +gboolean g_drive_is_media_removable (GDrive *drive); +gboolean g_drive_has_media (GDrive *drive); +gboolean g_drive_is_media_check_automatic (GDrive *drive); +gboolean g_drive_can_poll_for_media (GDrive *drive); +gboolean g_drive_can_eject (GDrive *drive); +void g_drive_eject (GDrive *drive, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean g_drive_eject_finish (GDrive *drive, + GAsyncResult *result, + GError **error); +void g_drive_poll_for_media (GDrive *drive, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean g_drive_poll_for_media_finish (GDrive *drive, + GAsyncResult *result, + GError **error); G_END_DECLS diff --git a/gio/gfile.c b/gio/gfile.c index 5ddc7fdea..0cbd91f40 100644 --- a/gio/gfile.c +++ b/gio/gfile.c @@ -929,14 +929,14 @@ g_file_query_filesystem_info (GFile *file, } /** - * g_file_find_enclosing_volume: + * g_file_find_enclosing_mount: * @file: input #GFile. * @cancellable: optional #GCancellable object, %NULL to ignore. * @error: a #GError. * - * Gets a #GVolume for the #GFile. + * Gets a #GMount for the #GFile. * - * If the #GFileIface for @file does not have a volume (e.g. possibly a + * If the #GFileIface for @file does not have a mount (e.g. possibly a * remote share), @error will be set to %G_IO_ERROR_NOT_FOUND and %NULL * will be returned. * @@ -944,10 +944,10 @@ g_file_query_filesystem_info (GFile *file, * triggering the cancellable object from another thread. If the operation * was cancelled, the error %G_IO_ERROR_CANCELLED will be returned. * - * Returns: a #GVolume where the @file is located or %NULL on error. + * Returns: a #GMount where the @file is located or %NULL on error. **/ -GVolume * -g_file_find_enclosing_volume (GFile *file, +GMount * +g_file_find_enclosing_mount (GFile *file, GCancellable *cancellable, GError **error) { @@ -959,15 +959,15 @@ g_file_find_enclosing_volume (GFile *file, return NULL; iface = G_FILE_GET_IFACE (file); - if (iface->find_enclosing_volume == NULL) + if (iface->find_enclosing_mount == NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, - _("Containing volume does not exist")); + _("Containing mount does not exist")); return NULL; } - return (* iface->find_enclosing_volume) (file, cancellable, error); + return (* iface->find_enclosing_mount) (file, cancellable, error); } /** diff --git a/gio/gfile.h b/gio/gfile.h index 67dce7ab4..49e24cb81 100644 --- a/gio/gfile.h +++ b/gio/gfile.h @@ -105,11 +105,11 @@ typedef struct _GDirectoryMonitor GDirectoryMonitor; typedef struct _GFileMonitor GFileMonitor; /** - * GVolume: + * GMount: * - * A handle to an object implementing the #GVolumeIface interface. + * A handle to an object implementing the #GMountIface interface. **/ -typedef struct _GVolume GVolume; /* Dummy typedef */ +typedef struct _GMount GMount; /* Dummy typedef */ /** * GFileProgressCallback: @@ -169,9 +169,9 @@ typedef gboolean (* GFileReadMoreCallback) (const char *file_contents, * @query_filesystem_info: Gets a #GFileInfo for the file system #GFile is on. * @_query_filesystem_info_async: Asynchronously gets a #GFileInfo for the file system #GFile is on. * @_query_filesystem_info_finish: Finishes asynchronously getting the file system info. - * @find_enclosing_volume: Gets a #GVolume for the #GFile. - * @find_enclosing_volume_async: Asynchronously gets the #GVolume for a #GFile. - * @find_enclosing_volume_finish: Finishes asynchronously getting the volume. + * @find_enclosing_mount: Gets a #GMount for the #GFile. + * @find_enclosing_mount_async: Asynchronously gets the #GMount for a #GFile. + * @find_enclosing_mount_finish: Finishes asynchronously getting the volume. * @set_display_name: Sets the display name for a #GFile. * @set_display_name_async: Asynchronously sets a #GFile's display name. * @set_display_name_finish: Finishes asynchronously setting a #GFile's display name. @@ -296,17 +296,17 @@ struct _GFileIface void (*_query_filesystem_info_async) (void); void (*_query_filesystem_info_finish) (void); - GVolume * (*find_enclosing_volume)(GFile *file, + GMount * (*find_enclosing_mount)(GFile *file, GCancellable *cancellable, GError **error); - void (*find_enclosing_volume_async)(GFile *file, - int io_priority, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - GVolume * (*find_enclosing_volume_finish)(GFile *file, - GAsyncResult *res, - GError **error); + void (*find_enclosing_mount_async)(GFile *file, + int io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + GMount * (*find_enclosing_mount_finish)(GFile *file, + GAsyncResult *res, + GError **error); GFile * (*set_display_name) (GFile *file, const char *display_name, @@ -608,9 +608,9 @@ GFileInfo * g_file_query_filesystem_info (GFile const char *attributes, GCancellable *cancellable, GError **error); -GVolume * g_file_find_enclosing_volume (GFile *file, - GCancellable *cancellable, - GError **error); +GMount * g_file_find_enclosing_mount (GFile *file, + GCancellable *cancellable, + GError **error); GFileEnumerator * g_file_enumerate_children (GFile *file, const char *attributes, GFileQueryInfoFlags flags, diff --git a/gio/gio.symbols b/gio/gio.symbols index 0fe74561c..d185ddba9 100644 --- a/gio/gio.symbols +++ b/gio/gio.symbols @@ -190,13 +190,15 @@ g_drive_get_name g_drive_get_icon g_drive_has_volumes g_drive_get_volumes -g_drive_is_automounted -g_drive_can_mount +g_drive_is_media_removable +g_drive_has_media +g_drive_is_media_check_automatic +g_drive_can_poll_for_media g_drive_can_eject -g_drive_mount -g_drive_mount_finish g_drive_eject g_drive_eject_finish +g_drive_poll_for_media +g_drive_poll_for_media_finish #endif #endif @@ -272,7 +274,7 @@ g_file_query_info g_file_query_info_async g_file_query_info_finish g_file_query_filesystem_info -g_file_find_enclosing_volume +g_file_find_enclosing_mount g_file_enumerate_children g_file_enumerate_children_async g_file_enumerate_children_finish @@ -650,7 +652,8 @@ g_unix_mount_get_device_path g_unix_mount_get_fs_type g_unix_mount_is_readonly g_unix_mount_is_system_internal -g_unix_mount_guess_type +g_unix_mount_guess_name +g_unix_mount_guess_icon g_unix_mount_point_compare g_unix_mount_point_get_mount_path g_unix_mount_point_get_device_path @@ -658,7 +661,8 @@ g_unix_mount_point_get_fs_type g_unix_mount_point_is_readonly g_unix_mount_point_is_user_mountable g_unix_mount_point_is_loopback -g_unix_mount_point_guess_type +g_unix_mount_point_guess_name +g_unix_mount_point_guess_icon g_get_unix_mount_points g_get_unix_mounts g_get_unix_mount_at @@ -666,6 +670,7 @@ g_unix_mounts_changed_since g_unix_mount_points_changed_since g_unix_mount_monitor_get_type G_GNUC_CONST g_unix_mount_monitor_new +g_unix_is_mount_path_system_internal #endif /* G_OS_UNIX */ #endif #endif @@ -688,27 +693,39 @@ g_unix_output_stream_new #endif #endif +#if IN_HEADER(__G_MOUNT_H__) +#if IN_FILE(__G_MOUNT_C__) +g_mount_get_type G_GNUC_CONST +g_mount_get_root +g_mount_get_name +g_mount_get_icon +g_mount_get_volume +g_mount_get_drive +g_mount_can_unmount +g_mount_unmount +g_mount_unmount_finish +#endif +#endif + #if IN_HEADER(__G_VOLUME_H__) #if IN_FILE(__G_VOLUME_C__) g_volume_get_type G_GNUC_CONST -g_volume_get_root g_volume_get_name g_volume_get_icon g_volume_get_drive -g_volume_can_unmount -g_volume_can_eject -g_volume_unmount -g_volume_unmount_finish -g_volume_eject -g_volume_eject_finish +g_volume_get_mount +g_volume_can_mount +g_volume_mount +g_volume_mount_finish #endif #endif #if IN_HEADER(__G_VOLUME_MONITOR_H__) #if IN_FILE(__G_VOLUME_MONITOR_C__) g_volume_monitor_get_type G_GNUC_CONST -g_volume_monitor_get_mounted_volumes g_volume_monitor_get_connected_drives +g_volume_monitor_get_volumes +g_volume_monitor_get_mounts #endif #if IN_FILE(__G_UNION_VOLUME_MONITOR_C__) g_volume_monitor_get diff --git a/gio/glocaldirectorymonitor.c b/gio/glocaldirectorymonitor.c index d620afc66..504706781 100644 --- a/gio/glocaldirectorymonitor.c +++ b/gio/glocaldirectorymonitor.c @@ -115,7 +115,7 @@ g_local_directory_monitor_constructor (GType type, #ifdef G_OS_WIN32 g_warning ("G_OS_WIN32: no mount emulation"); #else - GUnixMount *mount; + GUnixMountEntry *mount; /* Emulate unmount detection */ @@ -164,7 +164,7 @@ mounts_changed (GUnixMountMonitor *mount_monitor, gpointer user_data) { GLocalDirectoryMonitor *local_monitor = user_data; - GUnixMount *mount; + GUnixMountEntry *mount; gboolean is_mounted; GFile *file; diff --git a/gio/glocalfile.c b/gio/glocalfile.c index cb1e44390..1afa66ea7 100644 --- a/gio/glocalfile.c +++ b/gio/glocalfile.c @@ -75,7 +75,7 @@ #include "glocalfileoutputstream.h" #include "glocaldirectorymonitor.h" #include "glocalfilemonitor.h" -#include "gvolumeprivate.h" +#include "gmountprivate.h" #include #include "glibintl.h" @@ -697,7 +697,7 @@ get_mount_info (GFileInfo *fs_info, guint mount_info; char *mountpoint; dev_t *dev; - GUnixMount *mount; + GUnixMountEntry *mount; guint64 cache_time; if (g_lstat (path, &buf) != 0) @@ -871,21 +871,21 @@ g_local_file_query_filesystem_info (GFile *file, return info; } -static GVolume * -g_local_file_find_enclosing_volume (GFile *file, - GCancellable *cancellable, - GError **error) +static GMount * +g_local_file_find_enclosing_mount (GFile *file, + GCancellable *cancellable, + GError **error) { GLocalFile *local = G_LOCAL_FILE (file); struct stat buf; char *mountpoint; - GVolume *volume; + GMount *mount; if (g_lstat (local->filename, &buf) != 0) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, - _("Containing volume does not exist")); + _("Containing mount does not exist")); return NULL; } @@ -894,18 +894,18 @@ g_local_file_find_enclosing_volume (GFile *file, { g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, - _("Containing volume does not exist")); + _("Containing mount does not exist")); return NULL; } - volume = _g_volume_get_for_mount_path (mountpoint); + mount = _g_mount_get_for_mount_path (mountpoint); g_free (mountpoint); - if (volume) - return volume; + if (mount) + return mount; g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, - _("Containing volume does not exist")); + _("Containing mount does not exist")); return NULL; } @@ -1889,7 +1889,7 @@ g_local_file_file_iface_init (GFileIface *iface) iface->enumerate_children = g_local_file_enumerate_children; iface->query_info = g_local_file_query_info; iface->query_filesystem_info = g_local_file_query_filesystem_info; - iface->find_enclosing_volume = g_local_file_find_enclosing_volume; + iface->find_enclosing_mount = g_local_file_find_enclosing_mount; iface->query_settable_attributes = g_local_file_query_settable_attributes; iface->query_writable_namespaces = g_local_file_query_writable_namespaces; iface->set_attribute = g_local_file_set_attribute; diff --git a/gio/gmount.c b/gio/gmount.c new file mode 100644 index 000000000..49f917561 --- /dev/null +++ b/gio/gmount.c @@ -0,0 +1,312 @@ +/* GIO - GLib Input, Output and Streaming Library + * + * Copyright (C) 2006-2007 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Alexander Larsson + * David Zeuthen + */ + +#include +#include "gmount.h" +#include "gmountprivate.h" +#include "gsimpleasyncresult.h" +#include "glibintl.h" + +#include "gioalias.h" + +/** + * SECTION:gmount + * @short_description: mount management + * + * The #GMount interface represents user-visible mounts. Note, when + * porting from GnomeVFS, #GMount is the moral equivalent of + * #GnomeVFSVolume. + * + * Unmounting a #GMount instance is an asynchronous operation. For + * more information about asynchronous operations, see #GAsyncReady + * and #GSimpleAsyncReady. To unmount a #GMount instance, first call + * g_mount_unmount() with (at least) the #GMount instance and a + * #GAsyncReadyCallback. The callback will be fired when the + * operation has resolved (either with success or failure), and a + * #GAsyncReady structure will be passed to the callback. That + * callback should then call g_mount_unmount_finish() with the #GMount + * and the #GAsyncReady data to see if the operation was completed + * successfully. If an @error is present when + * g_mount_unmount_finish() is called, then it will be filled with any + * error information. + **/ + +static void g_mount_base_init (gpointer g_class); +static void g_mount_class_init (gpointer g_class, + gpointer class_data); + +GType +g_mount_get_type (void) +{ + static GType mount_type = 0; + + if (! mount_type) + { + static const GTypeInfo mount_info = + { + sizeof (GMountIface), /* class_size */ + g_mount_base_init, /* base_init */ + NULL, /* base_finalize */ + g_mount_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + 0, + 0, /* n_preallocs */ + NULL + }; + + mount_type = + g_type_register_static (G_TYPE_INTERFACE, I_("GMount"), + &mount_info, 0); + + g_type_interface_add_prerequisite (mount_type, G_TYPE_OBJECT); + } + + return mount_type; +} + +static void +g_mount_class_init (gpointer g_class, + gpointer class_data) +{ +} + +static void +g_mount_base_init (gpointer g_class) +{ + static gboolean initialized = FALSE; + + if (! initialized) + { + /** + * GMount::changed: + * + * Emitted when the mount has been changed. + **/ + g_signal_new (I_("changed"), + G_TYPE_MOUNT, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GMountIface, changed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + initialized = TRUE; + } +} + +/** + * g_mount_get_root: + * @mount: a #GMount. + * + * Gets the root directory on @mount. + * + * Returns: a #GFile. + **/ +GFile * +g_mount_get_root (GMount *mount) +{ + GMountIface *iface; + + g_return_val_if_fail (G_IS_MOUNT (mount), NULL); + + iface = G_MOUNT_GET_IFACE (mount); + + return (* iface->get_root) (mount); +} + +/** + * g_mount_get_name: + * @mount: a #GMount. + * + * Gets the name of @mount. + * + * Returns: the name for the given @mount. The returned string should + * be freed when no longer needed. + **/ +char * +g_mount_get_name (GMount *mount) +{ + GMountIface *iface; + + g_return_val_if_fail (G_IS_MOUNT (mount), NULL); + + iface = G_MOUNT_GET_IFACE (mount); + + return (* iface->get_name) (mount); +} + +/** + * g_mount_get_icon: + * @mount: a #GMount. + * + * Gets the icon for @mount. + * + * Returns: a #GIcon. + **/ +GIcon * +g_mount_get_icon (GMount *mount) +{ + GMountIface *iface; + + g_return_val_if_fail (G_IS_MOUNT (mount), NULL); + + iface = G_MOUNT_GET_IFACE (mount); + + return (* iface->get_icon) (mount); +} + +/** + * g_mount_get_volume: + * @mount: a #GMount. + * + * Gets the volume for the @mount. + * + * Returns: a #GVolume or %NULL if @mount is not associated with a volume. + **/ +GVolume * +g_mount_get_volume (GMount *mount) +{ + GMountIface *iface; + + g_return_val_if_fail (G_IS_MOUNT (mount), NULL); + + iface = G_MOUNT_GET_IFACE (mount); + + return (* iface->get_volume) (mount); +} + +/** + * g_mount_get_drive: + * @mount: a #GMount. + * + * Gets the drive for the @mount. + * + * This is a convenience method for getting the #GVolume and then + * using that object to get the #GDrive. + * + * Returns: a #GDrive or %NULL if @mount is not associated with a volume or a drive. + **/ +GDrive * +g_mount_get_drive (GMount *mount) +{ + GMountIface *iface; + + g_return_val_if_fail (G_IS_MOUNT (mount), NULL); + + iface = G_MOUNT_GET_IFACE (mount); + + return (* iface->get_drive) (mount); +} + +/** + * g_mount_can_unmount: + * @mount: a #GMount. + * + * Checks if @mount can be mounted. + * + * Returns: %TRUE if the @mount can be unmounted. + **/ +gboolean +g_mount_can_unmount (GMount *mount) +{ + GMountIface *iface; + + g_return_val_if_fail (G_IS_MOUNT (mount), FALSE); + + iface = G_MOUNT_GET_IFACE (mount); + + return (* iface->can_unmount) (mount); +} + +/** + * g_mount_unmount: + * @mount: a #GMount. + * @cancellable: optional #GCancellable object, %NULL to ignore. + * @callback: a #GAsyncReadyCallback. + * @user_data: user data passed to @callback. + * + * Unmounts a mount. This is an asynchronous operation, and is + * finished by calling g_mount_unmount_finish() with the @mount + * and #GAsyncResults data returned in the @callback. + **/ +void +g_mount_unmount (GMount *mount, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GMountIface *iface; + + g_return_if_fail (G_IS_MOUNT (mount)); + + iface = G_MOUNT_GET_IFACE (mount); + + if (iface->unmount == NULL) + { + g_simple_async_report_error_in_idle (G_OBJECT (mount), + callback, user_data, + G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + _("mount doesn't implement unmount")); + + return; + } + + (* iface->unmount) (mount, cancellable, callback, user_data); +} + +/** + * g_mount_unmount_finish: + * @mount: a #GMount. + * @result: a #GAsyncResult. + * @error: a #GError location to store the error occuring, or %NULL to + * ignore. + * + * Finishes unmounting a mount. If any errors occured during the operation, + * @error will be set to contain the errors and %FALSE will be returned. + * + * Returns: %TRUE if the mount was successfully unmounted. %FALSE otherwise. + **/ +gboolean +g_mount_unmount_finish (GMount *mount, + GAsyncResult *result, + GError **error) +{ + GMountIface *iface; + + g_return_val_if_fail (G_IS_MOUNT (mount), FALSE); + g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE); + + if (G_IS_SIMPLE_ASYNC_RESULT (result)) + { + GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result); + if (g_simple_async_result_propagate_error (simple, error)) + return FALSE; + } + + iface = G_MOUNT_GET_IFACE (mount); + return (* iface->unmount_finish) (mount, result, error); +} + +#define __G_MOUNT_C__ +#include "gioaliasdef.c" diff --git a/gio/gmount.h b/gio/gmount.h new file mode 100644 index 000000000..ed413e1e3 --- /dev/null +++ b/gio/gmount.h @@ -0,0 +1,123 @@ +/* GIO - GLib Input, Output and Streaming Library + * + * Copyright (C) 2006-2007 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Alexander Larsson + * David Zeuthen + */ + +#ifndef __G_MOUNT_H__ +#define __G_MOUNT_H__ + +#include +#include + +G_BEGIN_DECLS + +#define G_TYPE_MOUNT (g_mount_get_type ()) +#define G_MOUNT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_MOUNT, GMount)) +#define G_IS_MOUNT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), G_TYPE_MOUNT)) +#define G_MOUNT_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), G_TYPE_MOUNT, GMountIface)) + +/* GMount typedef is in gfile.h due to include order issues */ +/** + * GVolume: + * + * Opaque mountable volume object. + **/ +typedef struct _GVolume GVolume; /* Dummy typedef */ + +/** + * GDrive: + * + * Opaque drive object. + **/ +typedef struct _GDrive GDrive; /* Dummy typedef */ + +typedef struct _GMountIface GMountIface; + +/** + * GMountIface: + * @g_iface: The parent interface. + * @changed: Changed signal that is emitted when the mount's state has changed. + * @get_root: Gets a #GFile to the root directory of the #GMount. + * @get_name: Gets a string containing the name of the #GMount. + * @get_icon: Gets a #GIcon for the #GMount. + * @get_volume: Gets a #GVolume the mount is located on. Returns %NULL if the #GMount is not associated with a #GVolume. + * @get_drive: Gets a #GDrive the volume of the mount is located on. Returns %NULL if the #GMount is not associated with a #GDrive or a #GVolume. This is convenience method for getting the #GVolume and using that to get the #GDrive. + * @can_unmount: Checks if a #GMount can be unmounted. + * @unmount: Starts unmounting a #GMount. + * @unmount_finish: Finishes an unmounting operation. + * + * Interface for implementing operations for mounts. + **/ +struct _GMountIface +{ + GTypeInterface g_iface; + + /* signals */ + + void (*changed) (GMount *mount); + + /* Virtual Table */ + + GFile * (*get_root) (GMount *mount); + char * (*get_name) (GMount *mount); + GIcon * (*get_icon) (GMount *mount); + GVolume * (*get_volume) (GMount *mount); + GDrive * (*get_drive) (GMount *mount); + gboolean (*can_unmount) (GMount *mount); + void (*unmount) (GMount *mount, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + gboolean (*unmount_finish) (GMount *mount, + GAsyncResult *result, + GError **error); + + /*< private >*/ + /* Padding for future expansion */ + void (*_g_reserved1) (void); + void (*_g_reserved2) (void); + void (*_g_reserved3) (void); + void (*_g_reserved4) (void); + void (*_g_reserved5) (void); + void (*_g_reserved6) (void); + void (*_g_reserved7) (void); + void (*_g_reserved8) (void); +}; + +GType g_mount_get_type (void) G_GNUC_CONST; + +GFile * g_mount_get_root (GMount *mount); +char * g_mount_get_name (GMount *mount); +GIcon * g_mount_get_icon (GMount *mount); +GVolume * g_mount_get_volume (GMount *mount); +GDrive * g_mount_get_drive (GMount *mount); +gboolean g_mount_can_unmount (GMount *mount); +void g_mount_unmount (GMount *mount, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean g_mount_unmount_finish (GMount *mount, + GAsyncResult *result, + GError **error); + +G_END_DECLS + +#endif /* __G_MOUNT_H__ */ diff --git a/gio/gvolumeprivate.h b/gio/gmountprivate.h similarity index 94% rename from gio/gvolumeprivate.h rename to gio/gmountprivate.h index 43c9c1fe2..836613e48 100644 --- a/gio/gvolumeprivate.h +++ b/gio/gmountprivate.h @@ -27,7 +27,7 @@ G_BEGIN_DECLS -GVolume *_g_volume_get_for_mount_path (const char *mountpoint); +GMount *_g_mount_get_for_mount_path (const char *mount_path); G_END_DECLS diff --git a/gio/gnativevolumemonitor.h b/gio/gnativevolumemonitor.h index c3ccca2ee..688e98ef8 100644 --- a/gio/gnativevolumemonitor.h +++ b/gio/gnativevolumemonitor.h @@ -22,7 +22,7 @@ struct _GNativeVolumeMonitor { struct _GNativeVolumeMonitorClass { GVolumeMonitorClass parent_class; - GVolume * (*get_volume_for_mountpoint) (const char *mountpoint); + GMount * (*get_mount_for_mount_path) (const char *mount_path); int priority; }; diff --git a/gio/gunionvolumemonitor.c b/gio/gunionvolumemonitor.c index 63afd0c66..37e48cdf7 100644 --- a/gio/gunionvolumemonitor.c +++ b/gio/gunionvolumemonitor.c @@ -18,6 +18,7 @@ * Boston, MA 02111-1307, USA. * * Author: Alexander Larsson + * David Zeuthen */ #include @@ -26,7 +27,7 @@ #include #include "gunionvolumemonitor.h" -#include "gvolumeprivate.h" +#include "gmountprivate.h" #include "giomodule-priv.h" #ifdef G_OS_UNIX #include "gunixvolumemonitor.h" @@ -85,7 +86,7 @@ g_union_volume_monitor_dispose (GObject *object) } static GList * -get_mounted_volumes (GVolumeMonitor *volume_monitor) +get_mounts (GVolumeMonitor *volume_monitor) { GUnionVolumeMonitor *monitor; GVolumeMonitor *child_monitor; @@ -102,8 +103,33 @@ get_mounted_volumes (GVolumeMonitor *volume_monitor) { child_monitor = l->data; - res = g_list_concat (res, - g_volume_monitor_get_mounted_volumes (child_monitor)); + res = g_list_concat (res, g_volume_monitor_get_mounts (child_monitor)); + } + + G_UNLOCK (the_volume_monitor); + + return res; +} + +static GList * +get_volumes (GVolumeMonitor *volume_monitor) +{ + GUnionVolumeMonitor *monitor; + GVolumeMonitor *child_monitor; + GList *res; + GList *l; + + monitor = G_UNION_VOLUME_MONITOR (volume_monitor); + + res = NULL; + + G_LOCK (the_volume_monitor); + + for (l = monitor->monitors; l != NULL; l = l->next) + { + child_monitor = l->data; + + res = g_list_concat (res, g_volume_monitor_get_volumes (child_monitor)); } G_UNLOCK (the_volume_monitor); @@ -129,8 +155,7 @@ get_connected_drives (GVolumeMonitor *volume_monitor) { child_monitor = l->data; - res = g_list_concat (res, - g_volume_monitor_get_connected_drives (child_monitor)); + res = g_list_concat (res, g_volume_monitor_get_connected_drives (child_monitor)); } G_UNLOCK (the_volume_monitor); @@ -147,38 +172,80 @@ g_union_volume_monitor_class_init (GUnionVolumeMonitorClass *klass) gobject_class->finalize = g_union_volume_monitor_finalize; gobject_class->dispose = g_union_volume_monitor_dispose; - monitor_class->get_mounted_volumes = get_mounted_volumes; monitor_class->get_connected_drives = get_connected_drives; + monitor_class->get_volumes = get_volumes; + monitor_class->get_mounts = get_mounts; } static void -child_volume_mounted (GVolumeMonitor *child_monitor, - GVolume *child_volume, +child_volume_added (GVolumeMonitor *child_monitor, + GVolume *child_volume, + GUnionVolumeMonitor *union_monitor) +{ + g_signal_emit_by_name (union_monitor, + "volume_added", + child_volume); +} + +static void +child_volume_removed (GVolumeMonitor *child_monitor, + GVolume *child_volume, GUnionVolumeMonitor *union_monitor) { g_signal_emit_by_name (union_monitor, - "volume_mounted", + "volume_removed", child_volume); } static void -child_volume_pre_unmount (GVolumeMonitor *child_monitor, - GVolume *child_volume, +child_volume_changed (GVolumeMonitor *child_monitor, + GVolume *child_volume, + GUnionVolumeMonitor *union_monitor) +{ + g_signal_emit_by_name (union_monitor, + "volume_changed", + child_volume); +} + +static void +child_mount_added (GVolumeMonitor *child_monitor, + GMount *child_mount, + GUnionVolumeMonitor *union_monitor) +{ + g_signal_emit_by_name (union_monitor, + "mount_added", + child_mount); +} + +static void +child_mount_removed (GVolumeMonitor *child_monitor, + GMount *child_mount, + GUnionVolumeMonitor *union_monitor) +{ + g_signal_emit_by_name (union_monitor, + "mount_removed", + child_mount); +} + +static void +child_mount_pre_unmount (GVolumeMonitor *child_monitor, + GMount *child_mount, GUnionVolumeMonitor *union_monitor) { g_signal_emit_by_name (union_monitor, - "volume_pre_unmount", - child_volume); + "mount_pre_unmount", + child_mount); } + static void -child_volume_unmounted (GVolumeMonitor *child_monitor, - GVolume *child_volume, - GUnionVolumeMonitor *union_monitor) +child_mount_changed (GVolumeMonitor *child_monitor, + GMount *child_mount, + GUnionVolumeMonitor *union_monitor) { g_signal_emit_by_name (union_monitor, - "volume_unmounted", - child_volume); + "mount_changed", + child_mount); } static void @@ -201,6 +268,16 @@ child_drive_disconnected (GVolumeMonitor *child_monitor, child_drive); } +static void +child_drive_changed (GVolumeMonitor *child_monitor, + GDrive *child_drive, + GUnionVolumeMonitor *union_monitor) +{ + g_signal_emit_by_name (union_monitor, + "drive_changed", + child_drive); +} + static void g_union_volume_monitor_add_monitor (GUnionVolumeMonitor *union_monitor, GVolumeMonitor *volume_monitor) @@ -212,11 +289,16 @@ g_union_volume_monitor_add_monitor (GUnionVolumeMonitor *union_monitor, g_list_prepend (union_monitor->monitors, g_object_ref (volume_monitor)); - g_signal_connect (volume_monitor, "volume_mounted", (GCallback)child_volume_mounted, union_monitor); - g_signal_connect (volume_monitor, "volume_pre_unmount", (GCallback)child_volume_pre_unmount, union_monitor); - g_signal_connect (volume_monitor, "volume_unmounted", (GCallback)child_volume_unmounted, union_monitor); + g_signal_connect (volume_monitor, "volume_added", (GCallback)child_volume_added, union_monitor); + g_signal_connect (volume_monitor, "volume_removed", (GCallback)child_volume_removed, union_monitor); + g_signal_connect (volume_monitor, "volume_changed", (GCallback)child_volume_changed, union_monitor); + g_signal_connect (volume_monitor, "mount_added", (GCallback)child_mount_added, union_monitor); + g_signal_connect (volume_monitor, "mount_removed", (GCallback)child_mount_removed, union_monitor); + g_signal_connect (volume_monitor, "mount_pre_unmount", (GCallback)child_mount_pre_unmount, union_monitor); + g_signal_connect (volume_monitor, "mount_changed", (GCallback)child_mount_changed, union_monitor); g_signal_connect (volume_monitor, "drive_connected", (GCallback)child_drive_connected, union_monitor); g_signal_connect (volume_monitor, "drive_disconnected", (GCallback)child_drive_disconnected, union_monitor); + g_signal_connect (volume_monitor, "drive_changed", (GCallback)child_drive_changed, union_monitor); } static void @@ -231,11 +313,16 @@ g_union_volume_monitor_remove_monitor (GUnionVolumeMonitor *union_monitor, union_monitor->monitors = g_list_delete_link (union_monitor->monitors, l); - g_signal_handlers_disconnect_by_func (child_monitor, child_volume_mounted, union_monitor); - g_signal_handlers_disconnect_by_func (child_monitor, child_volume_pre_unmount, union_monitor); - g_signal_handlers_disconnect_by_func (child_monitor, child_volume_unmounted, union_monitor); + g_signal_handlers_disconnect_by_func (child_monitor, child_volume_added, union_monitor); + g_signal_handlers_disconnect_by_func (child_monitor, child_volume_removed, union_monitor); + g_signal_handlers_disconnect_by_func (child_monitor, child_volume_changed, union_monitor); + g_signal_handlers_disconnect_by_func (child_monitor, child_mount_added, union_monitor); + g_signal_handlers_disconnect_by_func (child_monitor, child_mount_removed, union_monitor); + g_signal_handlers_disconnect_by_func (child_monitor, child_mount_pre_unmount, union_monitor); + g_signal_handlers_disconnect_by_func (child_monitor, child_mount_changed, union_monitor); g_signal_handlers_disconnect_by_func (child_monitor, child_drive_connected, union_monitor); g_signal_handlers_disconnect_by_func (child_monitor, child_drive_disconnected, union_monitor); + g_signal_handlers_disconnect_by_func (child_monitor, child_drive_changed, union_monitor); } static gpointer @@ -369,32 +456,32 @@ g_volume_monitor_get (void) } /** - * g_volume_get_for_mount_path: + * _g_mount_get_for_mount_path: * @mountpoint: a string. * - * Returns: a #GVolume for given @mountpoint or %NULL. + * Returns: a #GMount for given @mount_path or %NULL. **/ -GVolume * -_g_volume_get_for_mount_path (const char *mountpoint) +GMount * +_g_mount_get_for_mount_path (const char *mount_path) { GType native_type; GNativeVolumeMonitorClass *klass; - GVolume *volume; + GMount *mount; native_type = get_native_type (); if (native_type == G_TYPE_INVALID) return NULL; - volume = NULL; + mount = NULL; klass = G_NATIVE_VOLUME_MONITOR_CLASS (g_type_class_ref (native_type)); - if (klass->get_volume_for_mountpoint) - volume = klass->get_volume_for_mountpoint (mountpoint); + if (klass->get_mount_for_mount_path) + mount = klass->get_mount_for_mount_path (mount_path); g_type_class_unref (klass); - return volume; + return mount; } #define __G_UNION_VOLUME_MONITOR_C__ diff --git a/gio/gunionvolumemonitor.h b/gio/gunionvolumemonitor.h index 6527dbf8f..fc9f4af94 100644 --- a/gio/gunionvolumemonitor.h +++ b/gio/gunionvolumemonitor.h @@ -18,6 +18,7 @@ * Boston, MA 02111-1307, USA. * * Author: Alexander Larsson + * David Zeuthen */ #ifndef __G_UNION_VOLUME_MONITOR_H__ diff --git a/gio/gunixdrive.c b/gio/gunixdrive.c deleted file mode 100644 index ab8eebfe9..000000000 --- a/gio/gunixdrive.c +++ /dev/null @@ -1,322 +0,0 @@ -/* GIO - GLib Input, Output and Streaming Library - * - * Copyright (C) 2006-2007 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General - * Public License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307, USA. - * - * Author: Alexander Larsson - */ - -#include - -#include - -#include -#include "gunixdrive.h" -#include "gunixvolume.h" -#include "gthemedicon.h" -#include "gvolumemonitor.h" -#include "glibintl.h" - -#include "gioalias.h" - -struct _GUnixDrive { - GObject parent; - - GUnixVolume *volume; /* owned by volume monitor */ - char *name; - char *icon; - char *mountpoint; - GUnixMountType guessed_type; -}; - -static void g_unix_volume_drive_iface_init (GDriveIface *iface); - -#define g_unix_drive_get_type _g_unix_drive_get_type -G_DEFINE_TYPE_WITH_CODE (GUnixDrive, g_unix_drive, G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (G_TYPE_DRIVE, - g_unix_volume_drive_iface_init)) - -static void -g_unix_drive_finalize (GObject *object) -{ - GUnixDrive *drive; - - drive = G_UNIX_DRIVE (object); - - if (drive->volume) - _g_unix_volume_unset_drive (drive->volume, drive); - - g_free (drive->name); - g_free (drive->icon); - g_free (drive->mountpoint); - - if (G_OBJECT_CLASS (g_unix_drive_parent_class)->finalize) - (*G_OBJECT_CLASS (g_unix_drive_parent_class)->finalize) (object); -} - -static void -g_unix_drive_class_init (GUnixDriveClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - - gobject_class->finalize = g_unix_drive_finalize; -} - -static void -g_unix_drive_init (GUnixDrive *unix_drive) -{ -} - -static char * -type_to_icon (GUnixMountType type) -{ - const char *icon_name = NULL; - - switch (type) - { - case G_UNIX_MOUNT_TYPE_HD: - icon_name = "drive-harddisk"; - break; - case G_UNIX_MOUNT_TYPE_FLOPPY: - case G_UNIX_MOUNT_TYPE_ZIP: - case G_UNIX_MOUNT_TYPE_JAZ: - case G_UNIX_MOUNT_TYPE_MEMSTICK: - icon_name = "drive-removable-media"; - break; - case G_UNIX_MOUNT_TYPE_CDROM: - icon_name = "drive-optical"; - break; - case G_UNIX_MOUNT_TYPE_NFS: - /* TODO: Would like a better icon here... */ - icon_name = "drive-removable-media"; - break; - case G_UNIX_MOUNT_TYPE_CAMERA: - icon_name = "camera-photo"; - break; - case G_UNIX_MOUNT_TYPE_IPOD: - icon_name = "multimedia-player"; - break; - case G_UNIX_MOUNT_TYPE_UNKNOWN: - default: - icon_name = "drive-removable-media"; - break; - } - return g_strdup (icon_name); -} - -/** - * g_unix_drive_new: - * @volume_monitor: a #GVolumeMonitor. - * @mountpoint: a #GUnixMountPoint. - * - * Returns: a #GUnixDrive for the given #GUnixMountPoint. - **/ -GUnixDrive * -_g_unix_drive_new (GVolumeMonitor *volume_monitor, - GUnixMountPoint *mountpoint) -{ - GUnixDrive *drive; - - if (!(g_unix_mount_point_is_user_mountable (mountpoint) || - g_str_has_prefix (g_unix_mount_point_get_device_path (mountpoint), "/vol/")) || - g_unix_mount_point_is_loopback (mountpoint)) - return NULL; - - drive = g_object_new (G_TYPE_UNIX_DRIVE, NULL); - - drive->guessed_type = g_unix_mount_point_guess_type (mountpoint); - - /* TODO: */ - drive->mountpoint = g_strdup (g_unix_mount_point_get_mount_path (mountpoint)); - drive->icon = type_to_icon (drive->guessed_type); - drive->name = g_strdup (_("Unknown drive")); - - return drive; -} - -/** - * g_unix_drive_disconnected: - * @drive: - * - **/ -void -_g_unix_drive_disconnected (GUnixDrive *drive) -{ - if (drive->volume) - { - _g_unix_volume_unset_drive (drive->volume, drive); - drive->volume = NULL; - } -} - -/** - * g_unix_drive_set_volume: - * @drive: - * @volume: - * - **/ -void -_g_unix_drive_set_volume (GUnixDrive *drive, - GUnixVolume *volume) -{ - if (drive->volume == volume) - return; - - if (drive->volume) - _g_unix_volume_unset_drive (drive->volume, drive); - - drive->volume = volume; - - /* TODO: Emit changed in idle to avoid locking issues */ - g_signal_emit_by_name (drive, "changed"); -} - -/** - * g_unix_drive_unset_volume: - * @drive: - * @volume: - * - **/ -void -_g_unix_drive_unset_volume (GUnixDrive *drive, - GUnixVolume *volume) -{ - if (drive->volume == volume) - { - drive->volume = NULL; - /* TODO: Emit changed in idle to avoid locking issues */ - g_signal_emit_by_name (drive, "changed"); - } -} - -static GIcon * -g_unix_drive_get_icon (GDrive *drive) -{ - GUnixDrive *unix_drive = G_UNIX_DRIVE (drive); - - return g_themed_icon_new (unix_drive->icon); -} - -static char * -g_unix_drive_get_name (GDrive *drive) -{ - GUnixDrive *unix_drive = G_UNIX_DRIVE (drive); - - return g_strdup (unix_drive->name); -} - -static gboolean -g_unix_drive_is_automounted (GDrive *drive) -{ - /* TODO */ - return FALSE; -} - -static gboolean -g_unix_drive_can_mount (GDrive *drive) -{ - /* TODO */ - return TRUE; -} - -static gboolean -g_unix_drive_can_eject (GDrive *drive) -{ - /* TODO */ - return FALSE; -} - -static GList * -g_unix_drive_get_volumes (GDrive *drive) -{ - GList *l; - GUnixDrive *unix_drive = G_UNIX_DRIVE (drive); - - l = NULL; - if (unix_drive->volume) - l = g_list_prepend (l, g_object_ref (unix_drive->volume)); - - return l; -} - -static gboolean -g_unix_drive_has_volumes (GDrive *drive) -{ - GUnixDrive *unix_drive = G_UNIX_DRIVE (drive); - - return unix_drive->volume != NULL; -} - - -gboolean -_g_unix_drive_has_mountpoint (GUnixDrive *drive, - const char *mountpoint) -{ - return strcmp (drive->mountpoint, mountpoint) == 0; -} - -static void -g_unix_drive_mount (GDrive *drive, - GMountOperation *mount_operation, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - /* TODO */ -} - - -static gboolean -g_unix_drive_mount_finish (GDrive *drive, - GAsyncResult *result, - GError **error) -{ - return TRUE; -} - -static void -g_unix_drive_eject (GDrive *drive, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - /* TODO */ -} - -static gboolean -g_unix_drive_eject_finish (GDrive *drive, - GAsyncResult *result, - GError **error) -{ - return TRUE; -} - -static void -g_unix_volume_drive_iface_init (GDriveIface *iface) -{ - iface->get_name = g_unix_drive_get_name; - iface->get_icon = g_unix_drive_get_icon; - iface->has_volumes = g_unix_drive_has_volumes; - iface->get_volumes = g_unix_drive_get_volumes; - iface->is_automounted = g_unix_drive_is_automounted; - iface->can_mount = g_unix_drive_can_mount; - iface->can_eject = g_unix_drive_can_eject; - iface->mount_fn = g_unix_drive_mount; - iface->mount_finish = g_unix_drive_mount_finish; - iface->eject = g_unix_drive_eject; - iface->eject_finish = g_unix_drive_eject_finish; -} diff --git a/gio/gunixdrive.h b/gio/gunixdrive.h deleted file mode 100644 index 788121006..000000000 --- a/gio/gunixdrive.h +++ /dev/null @@ -1,59 +0,0 @@ -/* GIO - GLib Input, Output and Streaming Library - * - * Copyright (C) 2006-2007 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General - * Public License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307, USA. - * - * Author: Alexander Larsson - */ - -#ifndef __G_UNIX_DRIVE_H__ -#define __G_UNIX_DRIVE_H__ - -#include -#include -#include -#include - -G_BEGIN_DECLS - -#define G_TYPE_UNIX_DRIVE (_g_unix_drive_get_type ()) -#define G_UNIX_DRIVE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_UNIX_DRIVE, GUnixDrive)) -#define G_UNIX_DRIVE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_UNIX_DRIVE, GUnixDriveClass)) -#define G_IS_UNIX_DRIVE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_UNIX_DRIVE)) -#define G_IS_UNIX_DRIVE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_UNIX_DRIVE)) - -typedef struct _GUnixDriveClass GUnixDriveClass; - -struct _GUnixDriveClass { - GObjectClass parent_class; -}; - -GType _g_unix_drive_get_type (void) G_GNUC_CONST; - -GUnixDrive *_g_unix_drive_new (GVolumeMonitor *volume_monitor, - GUnixMountPoint *mountpoint); -gboolean _g_unix_drive_has_mountpoint (GUnixDrive *drive, - const char *mountpoint); -void _g_unix_drive_set_volume (GUnixDrive *drive, - GUnixVolume *volume); -void _g_unix_drive_unset_volume (GUnixDrive *drive, - GUnixVolume *volume); -void _g_unix_drive_disconnected (GUnixDrive *drive); - -G_END_DECLS - -#endif /* __G_UNIX_DRIVE_H__ */ diff --git a/gio/gunixmount.c b/gio/gunixmount.c new file mode 100644 index 000000000..6246357a5 --- /dev/null +++ b/gio/gunixmount.c @@ -0,0 +1,348 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* GIO - GLib Input, Output and Streaming Library + * + * Copyright (C) 2006-2007 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Alexander Larsson + * David Zeuthen + */ + +#include + +#include +#include +#include + +#include +#include "gunixvolumemonitor.h" +#include "gunixmount.h" +#include "gunixvolume.h" +#include "gmountprivate.h" +#include "gvolumemonitor.h" +#include "gthemedicon.h" +#include "gsimpleasyncresult.h" +#include "glibintl.h" + +#include "gioalias.h" + +struct _GUnixMount { + GObject parent; + + GVolumeMonitor *volume_monitor; + + GUnixVolume *volume; /* owned by volume monitor */ + + char *name; + GIcon *icon; + char *device_path; + char *mount_path; +}; + +static void g_unix_mount_mount_iface_init (GMountIface *iface); + +#define g_unix_mount_get_type _g_unix_mount_get_type +G_DEFINE_TYPE_WITH_CODE (GUnixMount, g_unix_mount, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (G_TYPE_MOUNT, + g_unix_mount_mount_iface_init)) + + +static void +g_unix_mount_finalize (GObject *object) +{ + GUnixMount *mount; + + mount = G_UNIX_MOUNT (object); + + if (mount->volume_monitor != NULL) + g_object_unref (mount->volume_monitor); + + if (mount->volume) + _g_unix_volume_unset_mount (mount->volume, mount); + + //TODO: g_warn_if_fail (volume->volume == NULL); + g_object_unref (mount->icon); + g_free (mount->name); + g_free (mount->device_path); + g_free (mount->mount_path); + + if (G_OBJECT_CLASS (g_unix_mount_parent_class)->finalize) + (*G_OBJECT_CLASS (g_unix_mount_parent_class)->finalize) (object); +} + +static void +g_unix_mount_class_init (GUnixMountClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->finalize = g_unix_mount_finalize; +} + +static void +g_unix_mount_init (GUnixMount *unix_mount) +{ +} + +GUnixMount * +_g_unix_mount_new (GVolumeMonitor *volume_monitor, + GUnixMountEntry *mount_entry, + GUnixVolume *volume) +{ + GUnixMount *mount; + + /* No volume for mount: Ignore internal things */ + if (volume == NULL && g_unix_mount_is_system_internal (mount_entry)) + return NULL; + + mount = g_object_new (G_TYPE_UNIX_MOUNT, NULL); + mount->volume_monitor = volume_monitor != NULL ? g_object_ref (volume_monitor) : NULL; + mount->device_path = g_strdup (g_unix_mount_get_device_path (mount_entry)); + mount->mount_path = g_strdup (g_unix_mount_get_mount_path (mount_entry)); + mount->name = g_unix_mount_guess_name (mount_entry); + mount->icon = g_unix_mount_guess_icon (mount_entry); + + /* need to do this last */ + mount->volume = volume; + if (volume != NULL) + _g_unix_volume_set_mount (volume, mount); + + return mount; +} + +void +_g_unix_mount_unmounted (GUnixMount *mount) +{ + if (mount->volume != NULL) + { + _g_unix_volume_unset_mount (mount->volume, mount); + mount->volume = NULL; + g_signal_emit_by_name (mount, "changed"); + /* there's really no need to emit mount_changed on the volume monitor + * as we're going to be deleted.. */ + } +} + +void +_g_unix_mount_unset_volume (GUnixMount *mount, + GUnixVolume *volume) +{ + if (mount->volume == volume) + { + mount->volume = NULL; + /* TODO: Emit changed in idle to avoid locking issues */ + g_signal_emit_by_name (mount, "changed"); + if (mount->volume_monitor != NULL) + g_signal_emit_by_name (mount->volume_monitor, "mount_changed", mount); + } +} + +static GFile * +g_unix_mount_get_root (GMount *mount) +{ + GUnixMount *unix_mount = G_UNIX_MOUNT (mount); + + return g_file_new_for_path (unix_mount->mount_path); +} + +static GIcon * +g_unix_mount_get_icon (GMount *mount) +{ + GUnixMount *unix_mount = G_UNIX_MOUNT (mount); + + return g_object_ref (unix_mount->icon); +} + +static char * +g_unix_mount_get_name (GMount *mount) +{ + GUnixMount *unix_mount = G_UNIX_MOUNT (mount); + + return g_strdup (unix_mount->name); +} + +gboolean +_g_unix_mount_has_mount_path (GUnixMount *mount, + const char *mount_path) +{ + return strcmp (mount->mount_path, mount_path) == 0; +} + +static GDrive * +g_unix_mount_get_drive (GMount *mount) +{ + GUnixMount *unix_mount = G_UNIX_MOUNT (mount); + + if (unix_mount->volume != NULL) + return g_volume_get_drive (G_VOLUME (unix_mount->volume)); + + return NULL; +} + +static GVolume * +g_unix_mount_get_volume (GMount *mount) +{ + GUnixMount *unix_mount = G_UNIX_MOUNT (mount); + + if (unix_mount->volume) + return G_VOLUME (g_object_ref (unix_mount->volume)); + + return NULL; +} + +static gboolean +g_unix_mount_can_unmount (GMount *mount) +{ + return TRUE; +} + + +typedef struct { + GUnixMount *unix_mount; + GAsyncReadyCallback callback; + gpointer user_data; + GCancellable *cancellable; + int error_fd; + GIOChannel *error_channel; + guint error_channel_source_id; + GString *error_string; +} UnmountOp; + +static void +unmount_cb (GPid pid, gint status, gpointer user_data) +{ + UnmountOp *data = user_data; + GSimpleAsyncResult *simple; + + if (WEXITSTATUS (status) != 0) + { + GError *error; + error = g_error_new_literal (G_IO_ERROR, + G_IO_ERROR_FAILED, + data->error_string->str); + simple = g_simple_async_result_new_from_error (G_OBJECT (data->unix_mount), + data->callback, + data->user_data, + error); + g_error_free (error); + } + else + { + simple = g_simple_async_result_new (G_OBJECT (data->unix_mount), + data->callback, + data->user_data, + NULL); + } + + g_simple_async_result_complete (simple); + g_object_unref (simple); + + g_source_remove (data->error_channel_source_id); + g_io_channel_unref (data->error_channel); + g_string_free (data->error_string, TRUE); + close (data->error_fd); + g_spawn_close_pid (pid); + g_free (data); +} + +static gboolean +unmount_read_error (GIOChannel *channel, + GIOCondition condition, + gpointer user_data) +{ + char *str; + gsize str_len; + UnmountOp *data = user_data; + + g_io_channel_read_to_end (channel, &str, &str_len, NULL); + g_string_append (data->error_string, str); + g_free (str); + return TRUE; +} + +static void +g_unix_mount_unmount (GMount *mount, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GUnixMount *unix_mount = G_UNIX_MOUNT (mount); + UnmountOp *data; + GPid child_pid; + GError *error; + char *argv[] = {"umount", NULL, NULL}; + + if (unix_mount->mount_path != NULL) + argv[1] = unix_mount->mount_path; + else + argv[1] = unix_mount->device_path; + + data = g_new0 (UnmountOp, 1); + data->unix_mount = unix_mount; + data->callback = callback; + data->user_data = user_data; + data->cancellable = cancellable; + + error = NULL; + if (!g_spawn_async_with_pipes (NULL, /* working dir */ + argv, + NULL, /* envp */ + G_SPAWN_DO_NOT_REAP_CHILD|G_SPAWN_SEARCH_PATH, + NULL, /* child_setup */ + NULL, /* user_data for child_setup */ + &child_pid, + NULL, /* standard_input */ + NULL, /* standard_output */ + &(data->error_fd), + &error)) { + GSimpleAsyncResult *simple; + simple = g_simple_async_result_new_from_error (G_OBJECT (data->unix_mount), + data->callback, + data->user_data, + error); + g_simple_async_result_complete (simple); + g_object_unref (simple); + g_error_free (error); + g_free (data); + return; + } + data->error_string = g_string_new (""); + data->error_channel = g_io_channel_unix_new (data->error_fd); + data->error_channel_source_id = g_io_add_watch (data->error_channel, G_IO_IN, unmount_read_error, data); + g_child_watch_add (child_pid, unmount_cb, data); +} + +static gboolean +g_unix_mount_unmount_finish (GMount *mount, + GAsyncResult *result, + GError **error) +{ + return TRUE; +} + +static void +g_unix_mount_mount_iface_init (GMountIface *iface) +{ + iface->get_root = g_unix_mount_get_root; + iface->get_name = g_unix_mount_get_name; + iface->get_icon = g_unix_mount_get_icon; + iface->get_drive = g_unix_mount_get_drive; + iface->get_volume = g_unix_mount_get_volume; + iface->can_unmount = g_unix_mount_can_unmount; + iface->unmount = g_unix_mount_unmount; + iface->unmount_finish = g_unix_mount_unmount_finish; +} diff --git a/gio/gunixmount.h b/gio/gunixmount.h new file mode 100644 index 000000000..cafae799e --- /dev/null +++ b/gio/gunixmount.h @@ -0,0 +1,59 @@ +/* GIO - GLib Input, Output and Streaming Library + * + * Copyright (C) 2006-2007 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Alexander Larsson + * David Zeuthen + */ + +#ifndef __G_UNIX_MOUNT_H__ +#define __G_UNIX_MOUNT_H__ + +#include +#include +#include +#include + +G_BEGIN_DECLS + +#define G_TYPE_UNIX_MOUNT (_g_unix_mount_get_type ()) +#define G_UNIX_MOUNT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_UNIX_MOUNT, GUnixMount)) +#define G_UNIX_MOUNT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_UNIX_MOUNT, GUnixMountClass)) +#define G_IS_UNIX_MOUNT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_UNIX_MOUNT)) +#define G_IS_UNIX_MOUNT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_UNIX_MOUNT)) + +typedef struct _GUnixMountClass GUnixMountClass; + +struct _GUnixMountClass { + GObjectClass parent_class; +}; + +GType _g_unix_mount_get_type (void) G_GNUC_CONST; + +GUnixMount *_g_unix_mount_new (GVolumeMonitor *volume_monitor, + GUnixMountEntry *mount_entry, + GUnixVolume *volume); +gboolean _g_unix_mount_has_mount_path (GUnixMount *mount, + const char *mount_path); +void _g_unix_mount_unset_volume (GUnixMount *mount, + GUnixVolume *volume); +void _g_unix_mount_unmounted (GUnixMount *mount); + +G_END_DECLS + +#endif /* __G_UNIX_MOUNT_H__ */ diff --git a/gio/gunixmounts.c b/gio/gunixmounts.c index 069154cb6..51db6dc4d 100644 --- a/gio/gunixmounts.c +++ b/gio/gunixmounts.c @@ -1,3 +1,5 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + /* GIO - GLib Input, Output and Streaming Library * * Copyright (C) 2006-2007 Red Hat, Inc. @@ -46,9 +48,13 @@ #include "gunixmounts.h" #include "gfile.h" #include "gfilemonitor.h" +#include "glibintl.h" +#include "gthemedicon.h" #include "gioalias.h" +static const char *_resolve_dev_root (void); + /** * SECTION:gunixmounts * @short_description: Unix Mounts @@ -57,7 +63,41 @@ * **/ -struct _GUnixMount { +/** + * GUnixMountType: + * @G_UNIX_MOUNT_TYPE_UNKNOWN: Unknown UNIX mount type. + * @G_UNIX_MOUNT_TYPE_FLOPPY: Floppy disk UNIX mount type. + * @G_UNIX_MOUNT_TYPE_CDROM: CDROM UNIX mount type. + * @G_UNIX_MOUNT_TYPE_NFS: Network File System (NFS) UNIX mount type. + * @G_UNIX_MOUNT_TYPE_ZIP: ZIP UNIX mount type. + * @G_UNIX_MOUNT_TYPE_JAZ: JAZZ UNIX mount type. + * @G_UNIX_MOUNT_TYPE_MEMSTICK: Memory Stick UNIX mount type. + * @G_UNIX_MOUNT_TYPE_CF: Compact Flash UNIX mount type. + * @G_UNIX_MOUNT_TYPE_SM: Smart Media UNIX mount type. + * @G_UNIX_MOUNT_TYPE_SDMMC: SD/MMC UNIX mount type. + * @G_UNIX_MOUNT_TYPE_IPOD: iPod UNIX mount type. + * @G_UNIX_MOUNT_TYPE_CAMERA: Digital camera UNIX mount type. + * @G_UNIX_MOUNT_TYPE_HD: Hard drive UNIX mount type. + * + * Types of UNIX mounts. + **/ +typedef enum { + G_UNIX_MOUNT_TYPE_UNKNOWN, + G_UNIX_MOUNT_TYPE_FLOPPY, + G_UNIX_MOUNT_TYPE_CDROM, + G_UNIX_MOUNT_TYPE_NFS, + G_UNIX_MOUNT_TYPE_ZIP, + G_UNIX_MOUNT_TYPE_JAZ, + G_UNIX_MOUNT_TYPE_MEMSTICK, + G_UNIX_MOUNT_TYPE_CF, + G_UNIX_MOUNT_TYPE_SM, + G_UNIX_MOUNT_TYPE_SDMMC, + G_UNIX_MOUNT_TYPE_IPOD, + G_UNIX_MOUNT_TYPE_CAMERA, + G_UNIX_MOUNT_TYPE_HD +} GUnixMountType; + +struct _GUnixMountEntry { char *mount_path; char *device_path; char *filesystem_type; @@ -151,6 +191,63 @@ is_in (const char *value, const char *set[]) return FALSE; } +/** + * g_unix_is_mount_path_system_internal: + * @mount_path: a mount path, e.g. /media/disk or /usr + * + * Determines if @mount_path is considered an implementation of the + * OS. This is primarily used for hiding mountable and mounted volumes + * that only are used in the OS and has little to no relevance to the + * casual user. + * + * Returns; %TRUE if @mount_path is considered an implementation detail of the OS. + **/ +gboolean +g_unix_is_mount_path_system_internal (const char *mount_path) +{ + const char *ignore_mountpoints[] = { + /* Includes all FHS 2.3 toplevel dirs and other specilized + * directories that we want to hide from the user. + */ + "/", /* we already have "Filesystem root" in Nautilus */ + "/bin", + "/boot", + "/dev", + "/etc", + "/home", + "/lib", + "/lib64", + "/media", + "/mnt", + "/opt", + "/root", + "/sbin", + "/srv", + "/tmp", + "/usr", + "/var", + "/var/log/audit", /* https://bugzilla.redhat.com/show_bug.cgi?id=333041 */ + "/var/tmp", /* https://bugzilla.redhat.com/show_bug.cgi?id=335241 */ + "/proc", + "/sbin", + "/net", + NULL + }; + + if (is_in (mount_path, ignore_mountpoints)) + return TRUE; + + if (g_str_has_prefix (mount_path, "/dev") || + g_str_has_prefix (mount_path, "/proc") || + g_str_has_prefix (mount_path, "/sys")) + return TRUE; + + if (strstr (mount_path, "/.gvfs") != NULL) + return TRUE; + + return FALSE; +} + static gboolean guess_system_internal (const char *mountpoint, const char *fs, @@ -183,29 +280,6 @@ guess_system_internal (const char *mountpoint, "/dev/vn", NULL }; - const char *ignore_mountpoints[] = { - /* Includes all FHS 2.3 toplevel dirs */ - "/bin", - "/boot", - "/dev", - "/etc", - "/home", - "/lib", - "/lib64", - "/media", - "/mnt", - "/opt", - "/root", - "/sbin", - "/srv", - "/tmp", - "/usr", - "/var", - "/proc", - "/sbin", - "/net", - NULL - }; if (is_in (fs, ignore_fs)) return TRUE; @@ -213,15 +287,7 @@ guess_system_internal (const char *mountpoint, if (is_in (device, ignore_devices)) return TRUE; - if (is_in (mountpoint, ignore_mountpoints)) - return TRUE; - - if (g_str_has_prefix (mountpoint, "/dev") || - g_str_has_prefix (mountpoint, "/proc") || - g_str_has_prefix (mountpoint, "/sys")) - return TRUE; - - if (strstr (mountpoint, "/.gvfs") != NULL) + if (g_unix_is_mount_path_system_internal (mountpoint)) return TRUE; return FALSE; @@ -261,7 +327,7 @@ _g_get_unix_mounts () struct mntent *mntent; FILE *file; char *read_file; - GUnixMount *mount_entry; + GUnixMountEntry *mount_entry; GHashTable *mounts_hash; GList *return_list; @@ -291,11 +357,14 @@ _g_get_unix_mounts () if (mntent->mnt_fsname != NULL && mntent->mnt_fsname[0] == '/' && g_hash_table_lookup (mounts_hash, mntent->mnt_fsname)) - continue; + continue; - mount_entry = g_new0 (GUnixMount, 1); + mount_entry = g_new0 (GUnixMountEntry, 1); mount_entry->mount_path = g_strdup (mntent->mnt_dir); - mount_entry->device_path = g_strdup (mntent->mnt_fsname); + if (strcmp (mntent->mnt_fsname, "/dev/root") == 0) + mount_entry->device_path = g_strdup (_resolve_dev_root ()); + else + mount_entry->device_path = g_strdup (mntent->mnt_fsname); mount_entry->filesystem_type = g_strdup (mntent->mnt_type); #if defined (HAVE_HASMNTOPT) @@ -349,7 +418,7 @@ _g_get_unix_mounts (void) struct mnttab mntent; FILE *file; char *read_file; - GUnixMount *mount_entry; + GUnixMountEntry *mount_entry; GList *return_list; read_file = get_mtab_read_file (); @@ -363,7 +432,7 @@ _g_get_unix_mounts (void) G_LOCK (getmntent); while (! getmntent (file, &mntent)) { - mount_entry = g_new0 (GUnixMount, 1); + mount_entry = g_new0 (GUnixMountEntry, 1); mount_entry->mount_path = g_strdup (mntent.mnt_mountp); mount_entry->device_path = g_strdup (mntent.mnt_special); @@ -432,7 +501,7 @@ _g_get_unix_mounts (void) return_list = NULL; while (vmount_number > 0) { - mount_entry = g_new0 (GUnixMount, 1); + mount_entry = g_new0 (GUnixMountEntry, 1); mount_entry->device_path = g_strdup (vmt2dataptr (vmount_info, VMT_OBJECT)); mount_entry->mount_path = g_strdup (vmt2dataptr (vmount_info, VMT_STUB)); @@ -477,7 +546,7 @@ _g_get_unix_mounts (void) { struct statfs *mntent = NULL; int num_mounts, i; - GUnixMount *mount_entry; + GUnixMountEntry *mount_entry; GList *return_list; /* Pass MNT_NOWAIT to avoid blocking trying to update NFS mounts. */ @@ -488,7 +557,7 @@ _g_get_unix_mounts (void) for (i = 0; i < num_mounts; i++) { - mount_entry = g_new0 (GUnixMount, 1); + mount_entry = g_new0 (GUnixMountEntry, 1); mount_entry->mount_path = g_strdup (mntent[i].f_mntonname); mount_entry->device_path = g_strdup (mntent[i].f_mntfromname); @@ -554,10 +623,13 @@ _g_get_unix_mount_points (void) if ((strcmp (mntent->mnt_dir, "ignore") == 0) || (strcmp (mntent->mnt_dir, "swap") == 0)) continue; - + mount_entry = g_new0 (GUnixMountPoint, 1); mount_entry->mount_path = g_strdup (mntent->mnt_dir); - mount_entry->device_path = g_strdup (mntent->mnt_fsname); + if (strcmp (mntent->mnt_fsname, "/dev/root") == 0) + mount_entry->device_path = g_strdup (_resolve_dev_root ()); + else + mount_entry->device_path = g_strdup (mntent->mnt_fsname); mount_entry->filesystem_type = g_strdup (mntent->mnt_type); #ifdef HAVE_HASMNTOPT @@ -931,18 +1003,18 @@ g_get_unix_mounts (guint64 *time_read) * @mount_path: path for a possible unix mount. * @time_read: guint64 to contain a timestamp. * - * Gets a #GUnixMount for a given mount path. If @time_read + * Gets a #GUnixMountEntry for a given mount path. If @time_read * is set, it will be filled with a unix timestamp for checking * if the mounts have changed since with g_unix_mounts_changed_since(). * * Returns: a #GUnixMount. **/ -GUnixMount * +GUnixMountEntry * g_get_unix_mount_at (const char *mount_path, guint64 *time_read) { GList *mounts, *l; - GUnixMount *mount_entry, *found; + GUnixMountEntry *mount_entry, *found; mounts = g_get_unix_mounts (time_read); @@ -1156,7 +1228,7 @@ g_unix_mount_monitor_new (void) * Frees a unix mount. **/ void -g_unix_mount_free (GUnixMount *mount_entry) +g_unix_mount_free (GUnixMountEntry *mount_entry) { g_return_if_fail (mount_entry != NULL); @@ -1198,8 +1270,8 @@ strcmp_null (const char *str1, /** * g_unix_mount_compare: - * @mount1: first #GUnixMount to compare. - * @mount2: second #GUnixMount to compare. + * @mount1: first #GUnixMountEntry to compare. + * @mount2: second #GUnixMountEntry to compare. * * Compares two unix mounts. * @@ -1207,8 +1279,8 @@ strcmp_null (const char *str1, * or less than @mount2, respectively. **/ gint -g_unix_mount_compare (GUnixMount *mount1, - GUnixMount *mount2) +g_unix_mount_compare (GUnixMountEntry *mount1, + GUnixMountEntry *mount2) { int res; @@ -1235,14 +1307,14 @@ g_unix_mount_compare (GUnixMount *mount1, /** * g_unix_mount_get_mount_path: - * @mount_entry: input #GUnixMount to get the mount path for. + * @mount_entry: input #GUnixMountEntry to get the mount path for. * * Gets the mount path for a unix mount. * * Returns: the mount path for @mount_entry. **/ const char * -g_unix_mount_get_mount_path (GUnixMount *mount_entry) +g_unix_mount_get_mount_path (GUnixMountEntry *mount_entry) { g_return_val_if_fail (mount_entry != NULL, NULL); @@ -1258,7 +1330,7 @@ g_unix_mount_get_mount_path (GUnixMount *mount_entry) * Returns: a string containing the device path. **/ const char * -g_unix_mount_get_device_path (GUnixMount *mount_entry) +g_unix_mount_get_device_path (GUnixMountEntry *mount_entry) { g_return_val_if_fail (mount_entry != NULL, NULL); @@ -1274,7 +1346,7 @@ g_unix_mount_get_device_path (GUnixMount *mount_entry) * Returns: a string containing the file system type. **/ const char * -g_unix_mount_get_fs_type (GUnixMount *mount_entry) +g_unix_mount_get_fs_type (GUnixMountEntry *mount_entry) { g_return_val_if_fail (mount_entry != NULL, NULL); @@ -1290,7 +1362,7 @@ g_unix_mount_get_fs_type (GUnixMount *mount_entry) * Returns: %TRUE if @mount_entry is read only. **/ gboolean -g_unix_mount_is_readonly (GUnixMount *mount_entry) +g_unix_mount_is_readonly (GUnixMountEntry *mount_entry) { g_return_val_if_fail (mount_entry != NULL, FALSE); @@ -1306,7 +1378,7 @@ g_unix_mount_is_readonly (GUnixMount *mount_entry) * Returns: %TRUE if the unix mount is for a system path. **/ gboolean -g_unix_mount_is_system_internal (GUnixMount *mount_entry) +g_unix_mount_is_system_internal (GUnixMountEntry *mount_entry) { g_return_val_if_fail (mount_entry != NULL, FALSE); @@ -1560,7 +1632,7 @@ guess_mount_type (const char *mount_path, * Returns: a #GUnixMountType. **/ GUnixMountType -g_unix_mount_guess_type (GUnixMount *mount_entry) +g_unix_mount_guess_type (GUnixMountEntry *mount_entry) { g_return_val_if_fail (mount_entry != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN); g_return_val_if_fail (mount_entry->mount_path != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN); @@ -1594,5 +1666,273 @@ g_unix_mount_point_guess_type (GUnixMountPoint *mount_point) mount_point->filesystem_type); } +static const char * +type_to_icon (GUnixMountType type, gboolean is_mount_point) +{ + const char *icon_name; + + switch (type) + { + case G_UNIX_MOUNT_TYPE_HD: + if (is_mount_point) + icon_name = "drive-removable-media"; + else + icon_name = "drive-harddisk"; + break; + case G_UNIX_MOUNT_TYPE_FLOPPY: + case G_UNIX_MOUNT_TYPE_ZIP: + case G_UNIX_MOUNT_TYPE_JAZ: + if (is_mount_point) + icon_name = "drive-removable-media"; + else + icon_name = "media-floppy"; + break; + case G_UNIX_MOUNT_TYPE_CDROM: + if (is_mount_point) + icon_name = "drive-optical"; + else + icon_name = "media-optical"; + break; + case G_UNIX_MOUNT_TYPE_NFS: + /* TODO: Would like a better icon here... */ + if (is_mount_point) + icon_name = "drive-removable-media"; + else + icon_name = "drive-harddisk"; + break; + case G_UNIX_MOUNT_TYPE_MEMSTICK: + if (is_mount_point) + icon_name = "drive-removable-media"; + else + icon_name = "media-flash"; + break; + case G_UNIX_MOUNT_TYPE_CAMERA: + if (is_mount_point) + icon_name = "drive-removable-media"; + else + icon_name = "camera-photo"; + break; + case G_UNIX_MOUNT_TYPE_IPOD: + if (is_mount_point) + icon_name = "drive-removable-media"; + else + icon_name = "multimedia-player"; + break; + case G_UNIX_MOUNT_TYPE_UNKNOWN: + default: + if (is_mount_point) + icon_name = "drive-removable-media"; + else + icon_name = "drive-harddisk"; + break; + } + + return icon_name; +} + +char * +g_unix_mount_guess_name (GUnixMountEntry *mount_entry) +{ + char *name; + + if (strcmp (mount_entry->mount_path, "/") == 0) + name = g_strdup (_("Filesystem root")); + else + name = g_filename_display_basename (mount_entry->mount_path); + + return name; +} + +GIcon * +g_unix_mount_guess_icon (GUnixMountEntry *mount_entry) +{ + return g_themed_icon_new (type_to_icon (g_unix_mount_guess_type (mount_entry), FALSE)); +} + +char * +g_unix_mount_point_guess_name (GUnixMountPoint *mount_point) +{ + char *name; + + if (strcmp (mount_point->mount_path, "/") == 0) + name = g_strdup (_("Filesystem root")); + else + name = g_filename_display_basename (mount_point->mount_path); + + return name; +} + +GIcon * +g_unix_mount_point_guess_icon (GUnixMountPoint *mount_point) +{ + return g_themed_icon_new (type_to_icon (g_unix_mount_point_guess_type (mount_point), TRUE)); +} + + +/* borrowed from gtk/gtkfilesystemunix.c in GTK+ on 02/23/2006 */ +static void +_canonicalize_filename (gchar *filename) +{ + gchar *p, *q; + gboolean last_was_slash = FALSE; + + p = filename; + q = filename; + + while (*p) + { + if (*p == G_DIR_SEPARATOR) + { + if (!last_was_slash) + *q++ = G_DIR_SEPARATOR; + + last_was_slash = TRUE; + } + else + { + if (last_was_slash && *p == '.') + { + if (*(p + 1) == G_DIR_SEPARATOR || + *(p + 1) == '\0') + { + if (*(p + 1) == '\0') + break; + + p += 1; + } + else if (*(p + 1) == '.' && + (*(p + 2) == G_DIR_SEPARATOR || + *(p + 2) == '\0')) + { + if (q > filename + 1) + { + q--; + while (q > filename + 1 && + *(q - 1) != G_DIR_SEPARATOR) + q--; + } + + if (*(p + 2) == '\0') + break; + + p += 2; + } + else + { + *q++ = *p; + last_was_slash = FALSE; + } + } + else + { + *q++ = *p; + last_was_slash = FALSE; + } + } + + p++; + } + + if (q > filename + 1 && *(q - 1) == G_DIR_SEPARATOR) + q--; + + *q = '\0'; +} + +static char * +_resolve_symlink (const char *file) +{ + GError *error; + char *dir; + char *link; + char *f; + char *f1; + + f = g_strdup (file); + + while (g_file_test (f, G_FILE_TEST_IS_SYMLINK)) { + link = g_file_read_link (f, &error); + if (link == NULL) { + g_error_free (error); + g_free (f); + f = NULL; + goto out; + } + + dir = g_path_get_dirname (f); + f1 = g_strdup_printf ("%s/%s", dir, link); + g_free (dir); + g_free (link); + g_free (f); + f = f1; + } + + out: + if (f != NULL) + _canonicalize_filename (f); + return f; +} + +static const char * +_resolve_dev_root (void) +{ + static gboolean have_real_dev_root = FALSE; + static char real_dev_root[256]; + struct stat statbuf; + + /* see if it's cached already */ + if (have_real_dev_root) + goto found; + + /* otherwise we're going to find it right away.. */ + have_real_dev_root = TRUE; + + if (stat ("/dev/root", &statbuf) == 0) { + if (! S_ISLNK (statbuf.st_mode)) { + dev_t root_dev = statbuf.st_dev; + FILE *f; + char buf[1024]; + + /* see if device with similar major:minor as /dev/root is mention + * in /etc/mtab (it usually is) + */ + f = fopen ("/etc/mtab", "r"); + if (f != NULL) { + struct mntent ent; + + while (getmntent_r (f, &ent, buf, sizeof (buf)) != NULL) { + + if (stat (ent.mnt_fsname, &statbuf) == 0 && + statbuf.st_dev == root_dev) { + strncpy (real_dev_root, ent.mnt_fsname, sizeof (real_dev_root) - 1); + real_dev_root[sizeof (real_dev_root) - 1] = '\0'; + fclose (f); + goto found; + } + } + fclose (f); + } + + /* no, that didn't work.. next we could scan /dev ... but I digress.. */ + + } else { + char *resolved; + resolved = _resolve_symlink ("/dev/root"); + if (resolved != NULL) { + strncpy (real_dev_root, resolved, sizeof (real_dev_root) - 1); + real_dev_root[sizeof (real_dev_root) - 1] = '\0'; + g_free (resolved); + goto found; + } + } + } + + /* bah sucks.. */ + strcpy (real_dev_root, "/dev/root"); + + found: + return real_dev_root; +} + #define __G_UNIX_MOUNTS_C__ #include "gioaliasdef.c" diff --git a/gio/gunixmounts.h b/gio/gunixmounts.h index 401612c3f..1ad6f10ca 100644 --- a/gio/gunixmounts.h +++ b/gio/gunixmounts.h @@ -25,15 +25,16 @@ #include #include +#include G_BEGIN_DECLS /** - * GUnixMount: + * GUnixMountEntry: * - * Defines a Unix mount. + * Defines a Unix mount entry (e.g. "/media/cdrom"). **/ -typedef struct _GUnixMount GUnixMount; +typedef struct _GUnixMountEntry GUnixMountEntry; /** * GUnixMountPoint: @@ -42,40 +43,6 @@ typedef struct _GUnixMount GUnixMount; **/ typedef struct _GUnixMountPoint GUnixMountPoint; -/** - * GUnixMountType: - * @G_UNIX_MOUNT_TYPE_UNKNOWN: Unknown UNIX mount type. - * @G_UNIX_MOUNT_TYPE_FLOPPY: Floppy disk UNIX mount type. - * @G_UNIX_MOUNT_TYPE_CDROM: CDROM UNIX mount type. - * @G_UNIX_MOUNT_TYPE_NFS: Network File System (NFS) UNIX mount type. - * @G_UNIX_MOUNT_TYPE_ZIP: ZIP UNIX mount type. - * @G_UNIX_MOUNT_TYPE_JAZ: JAZZ UNIX mount type. - * @G_UNIX_MOUNT_TYPE_MEMSTICK: Memory Stick UNIX mount type. - * @G_UNIX_MOUNT_TYPE_CF: Compact Flash UNIX mount type. - * @G_UNIX_MOUNT_TYPE_SM: Smart Media UNIX mount type. - * @G_UNIX_MOUNT_TYPE_SDMMC: SD/MMC UNIX mount type. - * @G_UNIX_MOUNT_TYPE_IPOD: iPod UNIX mount type. - * @G_UNIX_MOUNT_TYPE_CAMERA: Digital camera UNIX mount type. - * @G_UNIX_MOUNT_TYPE_HD: Hard drive UNIX mount type. - * - * Types of UNIX mounts. - **/ -typedef enum { - G_UNIX_MOUNT_TYPE_UNKNOWN, - G_UNIX_MOUNT_TYPE_FLOPPY, - G_UNIX_MOUNT_TYPE_CDROM, - G_UNIX_MOUNT_TYPE_NFS, - G_UNIX_MOUNT_TYPE_ZIP, - G_UNIX_MOUNT_TYPE_JAZ, - G_UNIX_MOUNT_TYPE_MEMSTICK, - G_UNIX_MOUNT_TYPE_CF, - G_UNIX_MOUNT_TYPE_SM, - G_UNIX_MOUNT_TYPE_SDMMC, - G_UNIX_MOUNT_TYPE_IPOD, - G_UNIX_MOUNT_TYPE_CAMERA, - G_UNIX_MOUNT_TYPE_HD -} GUnixMountType; - /** * GUnixMountMonitor: * @@ -90,16 +57,17 @@ typedef struct _GUnixMountMonitorClass GUnixMountMonitorClass; #define G_IS_UNIX_MOUNT_MONITOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_UNIX_MOUNT_MONITOR)) #define G_IS_UNIX_MOUNT_MONITOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_UNIX_MOUNT_MONITOR)) -void g_unix_mount_free (GUnixMount *mount_entry); +void g_unix_mount_free (GUnixMountEntry *mount_entry); void g_unix_mount_point_free (GUnixMountPoint *mount_point); -gint g_unix_mount_compare (GUnixMount *mount1, - GUnixMount *mount2); -const char * g_unix_mount_get_mount_path (GUnixMount *mount_entry); -const char * g_unix_mount_get_device_path (GUnixMount *mount_entry); -const char * g_unix_mount_get_fs_type (GUnixMount *mount_entry); -gboolean g_unix_mount_is_readonly (GUnixMount *mount_entry); -gboolean g_unix_mount_is_system_internal (GUnixMount *mount_entry); -GUnixMountType g_unix_mount_guess_type (GUnixMount *mount_entry); +gint g_unix_mount_compare (GUnixMountEntry *mount1, + GUnixMountEntry *mount2); +const char * g_unix_mount_get_mount_path (GUnixMountEntry *mount_entry); +const char * g_unix_mount_get_device_path (GUnixMountEntry *mount_entry); +const char * g_unix_mount_get_fs_type (GUnixMountEntry *mount_entry); +gboolean g_unix_mount_is_readonly (GUnixMountEntry *mount_entry); +gboolean g_unix_mount_is_system_internal (GUnixMountEntry *mount_entry); +char * g_unix_mount_guess_name (GUnixMountEntry *mount_entry); +GIcon * g_unix_mount_guess_icon (GUnixMountEntry *mount_entry); gint g_unix_mount_point_compare (GUnixMountPoint *mount1, GUnixMountPoint *mount2); @@ -109,11 +77,12 @@ const char * g_unix_mount_point_get_fs_type (GUnixMountPoint *mount_p gboolean g_unix_mount_point_is_readonly (GUnixMountPoint *mount_point); gboolean g_unix_mount_point_is_user_mountable (GUnixMountPoint *mount_point); gboolean g_unix_mount_point_is_loopback (GUnixMountPoint *mount_point); -GUnixMountType g_unix_mount_point_guess_type (GUnixMountPoint *mount_point); +char * g_unix_mount_point_guess_name (GUnixMountPoint *mount_point); +GIcon * g_unix_mount_point_guess_icon (GUnixMountPoint *mount_point); GList * g_get_unix_mount_points (guint64 *time_read); GList * g_get_unix_mounts (guint64 *time_read); -GUnixMount * g_get_unix_mount_at (const char *mount_path, +GUnixMountEntry * g_get_unix_mount_at (const char *mount_path, guint64 *time_read); gboolean g_unix_mounts_changed_since (guint64 time); gboolean g_unix_mount_points_changed_since (guint64 time); @@ -121,6 +90,12 @@ gboolean g_unix_mount_points_changed_since (guint64 time); GType g_unix_mount_monitor_get_type (void) G_GNUC_CONST; GUnixMountMonitor *g_unix_mount_monitor_new (void); + + +char *g_unix_get_canonical_device_path (const char *device_path); + +gboolean g_unix_is_mount_path_system_internal (const char *mount_path); + G_END_DECLS #endif /* __G_UNIX_MOUNTS_H__ */ diff --git a/gio/gunixvolume.c b/gio/gunixvolume.c index 28e059813..1d7fafb4c 100644 --- a/gio/gunixvolume.c +++ b/gio/gunixvolume.c @@ -1,3 +1,5 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + /* GIO - GLib Input, Output and Streaming Library * * Copyright (C) 2006-2007 Red Hat, Inc. @@ -18,19 +20,21 @@ * Boston, MA 02111-1307, USA. * * Author: Alexander Larsson + * David Zeuthen */ #include #include +#include +#include #include -#include "gunixvolumemonitor.h" #include "gunixvolume.h" -#include "gunixdrive.h" -#include "gvolumeprivate.h" -#include "gvolumemonitor.h" +#include "gunixmount.h" #include "gthemedicon.h" +#include "gvolumemonitor.h" +#include "gsimpleasyncresult.h" #include "glibintl.h" #include "gioalias.h" @@ -38,10 +42,13 @@ struct _GUnixVolume { GObject parent; - GUnixDrive *drive; /* owned by volume monitor */ + GVolumeMonitor *volume_monitor; + GUnixMount *mount; /* owned by volume monitor */ + + char *device_path; + char *mount_path; char *name; - char *icon; - char *mountpoint; + GIcon *icon; }; static void g_unix_volume_volume_iface_init (GVolumeIface *iface); @@ -51,7 +58,6 @@ G_DEFINE_TYPE_WITH_CODE (GUnixVolume, g_unix_volume, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (G_TYPE_VOLUME, g_unix_volume_volume_iface_init)) - static void g_unix_volume_finalize (GObject *object) { @@ -59,14 +65,17 @@ g_unix_volume_finalize (GObject *object) volume = G_UNIX_VOLUME (object); - if (volume->drive) - _g_unix_drive_unset_volume (volume->drive, volume); - - g_warn_if_fail (volume->drive == NULL); - g_free (volume->name); - g_free (volume->icon); - g_free (volume->mountpoint); + if (volume->volume_monitor != NULL) + g_object_unref (volume->volume_monitor); + + if (volume->mount) + _g_unix_mount_unset_volume (volume->mount, volume); + g_object_unref (volume->icon); + g_free (volume->name); + g_free (volume->mount_path); + g_free (volume->device_path); + if (G_OBJECT_CLASS (g_unix_volume_parent_class)->finalize) (*G_OBJECT_CLASS (g_unix_volume_parent_class)->finalize) (object); } @@ -84,210 +93,261 @@ g_unix_volume_init (GUnixVolume *unix_volume) { } -static char * -get_filesystem_volume_name (const char *fs_type) -{ - /* TODO: add translation table from gnome-vfs */ - return g_strdup_printf (_("%s volume"), fs_type); -} - -static char * -type_to_icon (GUnixMountType type) -{ - const char *icon_name = NULL; - - switch (type) - { - case G_UNIX_MOUNT_TYPE_HD: - icon_name = "drive-harddisk"; - break; - case G_UNIX_MOUNT_TYPE_FLOPPY: - case G_UNIX_MOUNT_TYPE_ZIP: - case G_UNIX_MOUNT_TYPE_JAZ: - icon_name = "media-floppy"; - break; - case G_UNIX_MOUNT_TYPE_CDROM: - icon_name = "media-optical"; - break; - case G_UNIX_MOUNT_TYPE_NFS: - /* TODO: Would like a better icon here... */ - icon_name = "drive-harddisk"; - break; - case G_UNIX_MOUNT_TYPE_MEMSTICK: - icon_name = "media-flash"; - break; - case G_UNIX_MOUNT_TYPE_CAMERA: - icon_name = "camera-photo"; - break; - case G_UNIX_MOUNT_TYPE_IPOD: - icon_name = "multimedia-player"; - break; - case G_UNIX_MOUNT_TYPE_UNKNOWN: - default: - icon_name = "drive-harddisk"; - break; - } - return g_strdup (icon_name); -} - +/** + * g_unix_volume_new: + * @volume_monitor: a #GVolumeMonitor. + * @mountpoint: a #GUnixMountPoint. + * + * Returns: a #GUnixVolume for the given #GUnixMountPoint. + **/ GUnixVolume * -_g_unix_volume_new (GUnixMount *mount, - GUnixDrive *drive) +_g_unix_volume_new (GVolumeMonitor *volume_monitor, + GUnixMountPoint *mountpoint) { GUnixVolume *volume; - GUnixMountType type; - const char *mount_path; - char *volume_name; - mount_path = g_unix_mount_get_mount_path (mount); - - /* No drive for volume. Ignore internal things */ - if (drive == NULL && g_unix_mount_is_system_internal (mount)) + if (!(g_unix_mount_point_is_user_mountable (mountpoint) || + g_str_has_prefix (g_unix_mount_point_get_device_path (mountpoint), "/vol/")) || + g_unix_mount_point_is_loopback (mountpoint)) return NULL; volume = g_object_new (G_TYPE_UNIX_VOLUME, NULL); - volume->drive = drive; - if (drive) - _g_unix_drive_set_volume (drive, volume); - volume->mountpoint = g_strdup (mount_path); - - type = g_unix_mount_guess_type (mount); - - volume->icon = type_to_icon (type); - - volume_name = NULL; - if (mount_path) - { - if (strcmp (mount_path, "/") == 0) - volume_name = g_strdup (_("Filesystem root")); - else - volume_name = g_filename_display_basename (mount_path); - } - - if (volume_name == NULL) - { - if (g_unix_mount_get_fs_type (mount) != NULL) - volume_name = g_strdup (get_filesystem_volume_name (g_unix_mount_get_fs_type (mount))); - } - - if (volume_name == NULL) - /* TODO: Use volume size as name? */ - volume_name = g_strdup (_("Unknown volume")); - - volume->name = volume_name; + volume->volume_monitor = volume_monitor != NULL ? g_object_ref (volume_monitor) : NULL; + volume->mount_path = g_strdup (g_unix_mount_point_get_mount_path (mountpoint)); + volume->device_path = g_strdup (g_unix_mount_point_get_device_path (mountpoint)); + volume->name = g_unix_mount_point_guess_name (mountpoint); + volume->icon = g_unix_mount_point_guess_icon (mountpoint); return volume; } +/** + * g_unix_volume_disconnected: + * @volume: + * + **/ void -_g_unix_volume_unmounted (GUnixVolume *volume) +_g_unix_volume_disconnected (GUnixVolume *volume) { - if (volume->drive) + if (volume->mount) { - _g_unix_drive_unset_volume (volume->drive, volume); - volume->drive = NULL; - g_signal_emit_by_name (volume, "changed"); + _g_unix_mount_unset_volume (volume->mount, volume); + volume->mount = NULL; } } +/** + * g_unix_volume_set_mount: + * @volume: + * @mount: + * + **/ void -_g_unix_volume_unset_drive (GUnixVolume *volume, - GUnixDrive *drive) +_g_unix_volume_set_mount (GUnixVolume *volume, + GUnixMount *mount) { - if (volume->drive == drive) + if (volume->mount == mount) + return; + + if (volume->mount) + _g_unix_mount_unset_volume (volume->mount, volume); + + volume->mount = mount; + + /* TODO: Emit changed in idle to avoid locking issues */ + g_signal_emit_by_name (volume, "changed"); + if (volume->volume_monitor != NULL) + g_signal_emit_by_name (volume->volume_monitor, "volume_changed", volume); +} + +/** + * g_unix_volume_unset_mount: + * @volume: + * @mount: + * + **/ +void +_g_unix_volume_unset_mount (GUnixVolume *volume, + GUnixMount *mount) +{ + if (volume->mount == mount) { - volume->drive = NULL; + volume->mount = NULL; /* TODO: Emit changed in idle to avoid locking issues */ g_signal_emit_by_name (volume, "changed"); + if (volume->volume_monitor != NULL) + g_signal_emit_by_name (volume->volume_monitor, "volume_changed", volume); } } -static GFile * -g_unix_volume_get_root (GVolume *volume) -{ - GUnixVolume *unix_volume = G_UNIX_VOLUME (volume); - - return g_file_new_for_path (unix_volume->mountpoint); -} - static GIcon * g_unix_volume_get_icon (GVolume *volume) { GUnixVolume *unix_volume = G_UNIX_VOLUME (volume); - - return g_themed_icon_new (unix_volume->icon); + return g_object_ref (unix_volume->icon); } static char * g_unix_volume_get_name (GVolume *volume) { GUnixVolume *unix_volume = G_UNIX_VOLUME (volume); - return g_strdup (unix_volume->name); } -gboolean -_g_unix_volume_has_mountpoint (GUnixVolume *volume, - const char *mountpoint) +static gboolean +g_unix_volume_can_mount (GVolume *volume) { - return strcmp (volume->mountpoint, mountpoint) == 0; + return TRUE; } static GDrive * g_unix_volume_get_drive (GVolume *volume) { - GUnixVolume *unix_volume = G_UNIX_VOLUME (volume); - - if (unix_volume->drive) - return G_DRIVE (g_object_ref (unix_volume->drive)); - + /* TODO */ return NULL; } -static gboolean -g_unix_volume_can_unmount (GVolume *volume) +static GMount * +g_unix_volume_get_mount (GVolume *volume) { - /* TODO */ - return FALSE; + GUnixVolume *unix_volume = G_UNIX_VOLUME (volume); + + if (unix_volume->mount != NULL) + return g_object_ref (unix_volume->mount); + + return NULL; +} + + +gboolean +_g_unix_volume_has_mount_path (GUnixVolume *volume, + const char *mount_path) +{ + return strcmp (volume->mount_path, mount_path) == 0; +} + + +typedef struct { + GUnixVolume *unix_volume; + GAsyncReadyCallback callback; + gpointer user_data; + GCancellable *cancellable; + int error_fd; + GIOChannel *error_channel; + guint error_channel_source_id; + GString *error_string; +} MountOp; + +static void +mount_cb (GPid pid, gint status, gpointer user_data) +{ + MountOp *data = user_data; + GSimpleAsyncResult *simple; + + if (WEXITSTATUS (status) != 0) + { + GError *error; + error = g_error_new_literal (G_IO_ERROR, + G_IO_ERROR_FAILED, + data->error_string->str); + simple = g_simple_async_result_new_from_error (G_OBJECT (data->unix_volume), + data->callback, + data->user_data, + error); + g_error_free (error); + } + else + { + simple = g_simple_async_result_new (G_OBJECT (data->unix_volume), + data->callback, + data->user_data, + NULL); + } + + g_simple_async_result_complete (simple); + g_object_unref (simple); + + g_source_remove (data->error_channel_source_id); + g_io_channel_unref (data->error_channel); + g_string_free (data->error_string, TRUE); + close (data->error_fd); + g_spawn_close_pid (pid); + g_free (data); } static gboolean -g_unix_volume_can_eject (GVolume *volume) +mount_read_error (GIOChannel *channel, + GIOCondition condition, + gpointer user_data) { - /* TODO */ - return FALSE; -} + char *str; + gsize str_len; + MountOp *data = user_data; -static void -g_unix_volume_unmount (GVolume *volume, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - /* TODO */ -} - -static gboolean -g_unix_volume_unmount_finish (GVolume *volume, - GAsyncResult *result, - GError **error) -{ + g_io_channel_read_to_end (channel, &str, &str_len, NULL); + g_string_append (data->error_string, str); + g_free (str); return TRUE; } static void -g_unix_volume_eject (GVolume *volume, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) +g_unix_volume_mount (GVolume *volume, + GMountOperation *mount_operation, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { - /* TODO */ + GUnixVolume *unix_volume = G_UNIX_VOLUME (volume); + MountOp *data; + GPid child_pid; + GError *error; + char *argv[] = {"mount", NULL, NULL}; + + if (unix_volume->mount_path != NULL) + argv[1] = unix_volume->mount_path; + else + argv[1] = unix_volume->device_path; + + data = g_new0 (MountOp, 1); + data->unix_volume = unix_volume; + data->callback = callback; + data->user_data = user_data; + data->cancellable = cancellable; + + error = NULL; + if (!g_spawn_async_with_pipes (NULL, /* working dir */ + argv, + NULL, /* envp */ + G_SPAWN_DO_NOT_REAP_CHILD|G_SPAWN_SEARCH_PATH, + NULL, /* child_setup */ + NULL, /* user_data for child_setup */ + &child_pid, + NULL, /* standard_input */ + NULL, /* standard_output */ + &(data->error_fd), + &error)) { + GSimpleAsyncResult *simple; + simple = g_simple_async_result_new_from_error (G_OBJECT (data->unix_volume), + data->callback, + data->user_data, + error); + g_simple_async_result_complete (simple); + g_object_unref (simple); + g_error_free (error); + g_free (data); + return; + } + data->error_string = g_string_new (""); + data->error_channel = g_io_channel_unix_new (data->error_fd); + data->error_channel_source_id = g_io_add_watch (data->error_channel, G_IO_IN, mount_read_error, data); + g_child_watch_add (child_pid, mount_cb, data); } + static gboolean -g_unix_volume_eject_finish (GVolume *volume, - GAsyncResult *result, - GError **error) +g_unix_volume_mount_finish (GVolume *volume, + GAsyncResult *result, + GError **error) { return TRUE; } @@ -295,14 +355,11 @@ g_unix_volume_eject_finish (GVolume *volume, static void g_unix_volume_volume_iface_init (GVolumeIface *iface) { - iface->get_root = g_unix_volume_get_root; iface->get_name = g_unix_volume_get_name; iface->get_icon = g_unix_volume_get_icon; iface->get_drive = g_unix_volume_get_drive; - iface->can_unmount = g_unix_volume_can_unmount; - iface->can_eject = g_unix_volume_can_eject; - iface->unmount = g_unix_volume_unmount; - iface->unmount_finish = g_unix_volume_unmount_finish; - iface->eject = g_unix_volume_eject; - iface->eject_finish = g_unix_volume_eject_finish; + iface->get_mount = g_unix_volume_get_mount; + iface->can_mount = g_unix_volume_can_mount; + iface->mount_fn = g_unix_volume_mount; + iface->mount_finish = g_unix_volume_mount_finish; } diff --git a/gio/gunixvolume.h b/gio/gunixvolume.h index 575679853..8e6e2254d 100644 --- a/gio/gunixvolume.h +++ b/gio/gunixvolume.h @@ -18,6 +18,7 @@ * Boston, MA 02111-1307, USA. * * Author: Alexander Larsson + * David Zeuthen */ #ifndef __G_UNIX_VOLUME_H__ @@ -44,13 +45,15 @@ struct _GUnixVolumeClass { GType _g_unix_volume_get_type (void) G_GNUC_CONST; -GUnixVolume *_g_unix_volume_new (GUnixMount *mount, - GUnixDrive *drive); -gboolean _g_unix_volume_has_mountpoint (GUnixVolume *volume, - const char *mountpoint); -void _g_unix_volume_unset_drive (GUnixVolume *volume, - GUnixDrive *drive); -void _g_unix_volume_unmounted (GUnixVolume *volume); +GUnixVolume *_g_unix_volume_new (GVolumeMonitor *volume_monitor, + GUnixMountPoint *mountpoint); +gboolean _g_unix_volume_has_mount_path (GUnixVolume *volume, + const char *mount_path); +void _g_unix_volume_set_mount (GUnixVolume *volume, + GUnixMount *mount); +void _g_unix_volume_unset_mount (GUnixVolume *volume, + GUnixMount *mount); +void _g_unix_volume_disconnected (GUnixVolume *volume); G_END_DECLS diff --git a/gio/gunixvolumemonitor.c b/gio/gunixvolumemonitor.c index 43475f587..395a8206a 100644 --- a/gio/gunixvolumemonitor.c +++ b/gio/gunixvolumemonitor.c @@ -1,3 +1,5 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + /* GIO - GLib Input, Output and Streaming Library * * Copyright (C) 2006-2007 Red Hat, Inc. @@ -18,6 +20,7 @@ * Boston, MA 02111-1307, USA. * * Author: Alexander Larsson + * David Zeuthen */ #include @@ -27,9 +30,9 @@ #include #include "gunixvolumemonitor.h" #include "gunixmounts.h" +#include "gunixmount.h" #include "gunixvolume.h" -#include "gunixdrive.h" -#include "gvolumeprivate.h" +#include "gmountprivate.h" #include "glibintl.h" #include "gioalias.h" @@ -42,16 +45,16 @@ struct _GUnixVolumeMonitor { GList *last_mountpoints; GList *last_mounts; - GList *drives; GList *volumes; + GList *mounts; }; -static void mountpoints_changed (GUnixMountMonitor *mount_monitor, - gpointer user_data); -static void mounts_changed (GUnixMountMonitor *mount_monitor, - gpointer user_data); -static void update_drives (GUnixVolumeMonitor *monitor); -static void update_volumes (GUnixVolumeMonitor *monitor); +static void mountpoints_changed (GUnixMountMonitor *mount_monitor, + gpointer user_data); +static void mounts_changed (GUnixMountMonitor *mount_monitor, + gpointer user_data); +static void update_volumes (GUnixVolumeMonitor *monitor); +static void update_mounts (GUnixVolumeMonitor *monitor); #define g_unix_volume_monitor_get_type _g_unix_volume_monitor_get_type G_DEFINE_TYPE (GUnixVolumeMonitor, g_unix_volume_monitor, G_TYPE_NATIVE_VOLUME_MONITOR); @@ -68,20 +71,36 @@ g_unix_volume_monitor_finalize (GObject *object) g_object_unref (monitor->mount_monitor); + g_list_foreach (monitor->last_mountpoints, (GFunc)g_unix_mount_point_free, NULL); + g_list_free (monitor->last_mountpoints); g_list_foreach (monitor->last_mounts, (GFunc)g_unix_mount_free, NULL); g_list_free (monitor->last_mounts); g_list_foreach (monitor->volumes, (GFunc)g_object_unref, NULL); g_list_free (monitor->volumes); - g_list_foreach (monitor->drives, (GFunc)g_object_unref, NULL); - g_list_free (monitor->drives); + g_list_foreach (monitor->mounts, (GFunc)g_object_unref, NULL); + g_list_free (monitor->mounts); if (G_OBJECT_CLASS (g_unix_volume_monitor_parent_class)->finalize) (*G_OBJECT_CLASS (g_unix_volume_monitor_parent_class)->finalize) (object); } static GList * -get_mounted_volumes (GVolumeMonitor *volume_monitor) +get_mounts (GVolumeMonitor *volume_monitor) +{ + GUnixVolumeMonitor *monitor; + GList *l; + + monitor = G_UNIX_VOLUME_MONITOR (volume_monitor); + + l = g_list_copy (monitor->mounts); + g_list_foreach (l, (GFunc)g_object_ref, NULL); + + return l; +} + +static GList * +get_volumes (GVolumeMonitor *volume_monitor) { GUnixVolumeMonitor *monitor; GList *l; @@ -97,29 +116,21 @@ get_mounted_volumes (GVolumeMonitor *volume_monitor) static GList * get_connected_drives (GVolumeMonitor *volume_monitor) { - GUnixVolumeMonitor *monitor; - GList *l; - - monitor = G_UNIX_VOLUME_MONITOR (volume_monitor); - - l = g_list_copy (monitor->drives); - g_list_foreach (l, (GFunc)g_object_ref, NULL); - - return l; + return NULL; } -static GVolume * -get_volume_for_mountpoint (const char *mountpoint) +static GMount * +get_mount_for_mount_path (const char *mount_path) { + GUnixMountEntry *mount_entry; GUnixMount *mount; - GUnixVolume *volume; - mount = g_get_unix_mount_at (mountpoint, NULL); + mount_entry = g_get_unix_mount_at (mount_path, NULL); - /* TODO: Set drive? */ - volume = _g_unix_volume_new (mount, NULL); + /* TODO: Set mountable volume? */ + mount = _g_unix_mount_new (NULL, mount_entry, NULL); - return G_VOLUME (volume); + return G_MOUNT (mount); } static void @@ -131,11 +142,12 @@ g_unix_volume_monitor_class_init (GUnixVolumeMonitorClass *klass) gobject_class->finalize = g_unix_volume_monitor_finalize; - monitor_class->get_mounted_volumes = get_mounted_volumes; + monitor_class->get_mounts = get_mounts; + monitor_class->get_volumes = get_volumes; monitor_class->get_connected_drives = get_connected_drives; native_class->priority = 0; - native_class->get_volume_for_mountpoint = get_volume_for_mountpoint; + native_class->get_mount_for_mount_path = get_mount_for_mount_path; } static void @@ -144,9 +156,9 @@ mountpoints_changed (GUnixMountMonitor *mount_monitor, { GUnixVolumeMonitor *unix_monitor = user_data; - /* Update both to make sure drives are created before volumes */ - update_drives (unix_monitor); + /* Update both to make sure volumes are created before mounts */ update_volumes (unix_monitor); + update_mounts (unix_monitor); } static void @@ -155,9 +167,9 @@ mounts_changed (GUnixMountMonitor *mount_monitor, { GUnixVolumeMonitor *unix_monitor = user_data; - /* Update both to make sure drives are created before volumes */ - update_drives (unix_monitor); + /* Update both to make sure volumes are created before mounts */ update_volumes (unix_monitor); + update_mounts (unix_monitor); } static void @@ -174,9 +186,8 @@ g_unix_volume_monitor_init (GUnixVolumeMonitor *unix_monitor) "mountpoints_changed", G_CALLBACK (mountpoints_changed), unix_monitor); - update_drives (unix_monitor); update_volumes (unix_monitor); - + update_mounts (unix_monitor); } /** @@ -239,32 +250,15 @@ diff_sorted_lists (GList *list1, } /** - * g_unix_volume_lookup_drive_for_mountpoint: + * _g_unix_volume_monitor_lookup_volume_for_mount_path: * @monitor: - * @mountpoint: + * @mount_path: * - * Returns: #GUnixDrive for the given @mountpoint. + * Returns: #GUnixVolume for the given @mount_path. **/ -GUnixDrive * -_g_unix_volume_monitor_lookup_drive_for_mountpoint (GUnixVolumeMonitor *monitor, - const char *mountpoint) -{ - GList *l; - - for (l = monitor->drives; l != NULL; l = l->next) - { - GUnixDrive *drive = l->data; - - if (_g_unix_drive_has_mountpoint (drive, mountpoint)) - return drive; - } - - return NULL; -} - -static GUnixVolume * -find_volume_by_mountpoint (GUnixVolumeMonitor *monitor, - const char *mountpoint) +GUnixVolume * +_g_unix_volume_monitor_lookup_volume_for_mount_path (GUnixVolumeMonitor *monitor, + const char *mount_path) { GList *l; @@ -272,20 +266,37 @@ find_volume_by_mountpoint (GUnixVolumeMonitor *monitor, { GUnixVolume *volume = l->data; - if (_g_unix_volume_has_mountpoint (volume, mountpoint)) + if (_g_unix_volume_has_mount_path (volume, mount_path)) return volume; } return NULL; } +static GUnixMount * +find_mount_by_mountpath (GUnixVolumeMonitor *monitor, + const char *mount_path) +{ + GList *l; + + for (l = monitor->mounts; l != NULL; l = l->next) + { + GUnixMount *mount = l->data; + + if (_g_unix_mount_has_mount_path (mount, mount_path)) + return mount; + } + + return NULL; +} + static void -update_drives (GUnixVolumeMonitor *monitor) +update_volumes (GUnixVolumeMonitor *monitor) { GList *new_mountpoints; GList *removed, *added; GList *l; - GUnixDrive *drive; + GUnixVolume *volume; new_mountpoints = g_get_unix_mount_points (NULL); @@ -299,14 +310,14 @@ update_drives (GUnixVolumeMonitor *monitor) { GUnixMountPoint *mountpoint = l->data; - drive = _g_unix_volume_monitor_lookup_drive_for_mountpoint (monitor, - g_unix_mount_point_get_mount_path (mountpoint)); - if (drive) + volume = _g_unix_volume_monitor_lookup_volume_for_mount_path (monitor, + g_unix_mount_point_get_mount_path (mountpoint)); + if (volume) { - _g_unix_drive_disconnected (drive); - monitor->drives = g_list_remove (monitor->drives, drive); - g_signal_emit_by_name (monitor, "drive_disconnected", drive); - g_object_unref (drive); + _g_unix_volume_disconnected (volume); + monitor->volumes = g_list_remove (monitor->volumes, volume); + g_signal_emit_by_name (monitor, "volume_removed", volume); + g_object_unref (volume); } } @@ -314,11 +325,11 @@ update_drives (GUnixVolumeMonitor *monitor) { GUnixMountPoint *mountpoint = l->data; - drive = _g_unix_drive_new (G_VOLUME_MONITOR (monitor), mountpoint); - if (drive) + volume = _g_unix_volume_new (G_VOLUME_MONITOR (monitor), mountpoint); + if (volume) { - monitor->drives = g_list_prepend (monitor->drives, drive); - g_signal_emit_by_name (monitor, "drive_connected", drive); + monitor->volumes = g_list_prepend (monitor->volumes, volume); + g_signal_emit_by_name (monitor, "volume_added", volume); } } @@ -331,13 +342,13 @@ update_drives (GUnixVolumeMonitor *monitor) } static void -update_volumes (GUnixVolumeMonitor *monitor) +update_mounts (GUnixVolumeMonitor *monitor) { GList *new_mounts; GList *removed, *added; GList *l; + GUnixMount *mount; GUnixVolume *volume; - GUnixDrive *drive; const char *mount_path; new_mounts = g_get_unix_mounts (NULL); @@ -350,31 +361,34 @@ update_volumes (GUnixVolumeMonitor *monitor) for (l = removed; l != NULL; l = l->next) { - GUnixMount *mount = l->data; + GUnixMountEntry *mount_entry = l->data; - volume = find_volume_by_mountpoint (monitor, g_unix_mount_get_mount_path (mount)); - if (volume) + g_warning ("%s %s removed", + g_unix_mount_get_mount_path (mount_entry), + g_unix_mount_get_device_path (mount_entry)); + + mount = find_mount_by_mountpath (monitor, g_unix_mount_get_mount_path (mount_entry)); + if (mount) { - _g_unix_volume_unmounted (volume); - monitor->volumes = g_list_remove (monitor->volumes, volume); - g_signal_emit_by_name (monitor, "volume_unmounted", volume); - g_object_unref (volume); + _g_unix_mount_unmounted (mount); + monitor->mounts = g_list_remove (monitor->mounts, mount); + g_signal_emit_by_name (monitor, "mount_removed", mount); + g_object_unref (mount); } } for (l = added; l != NULL; l = l->next) { - GUnixMount *mount = l->data; + GUnixMountEntry *mount_entry = l->data; - mount_path = g_unix_mount_get_mount_path (mount); + mount_path = g_unix_mount_get_mount_path (mount_entry); - drive = _g_unix_volume_monitor_lookup_drive_for_mountpoint (monitor, - mount_path); - volume = _g_unix_volume_new (mount, drive); - if (volume) + volume = _g_unix_volume_monitor_lookup_volume_for_mount_path (monitor, mount_path); + mount = _g_unix_mount_new (G_VOLUME_MONITOR (monitor), mount_entry, volume); + if (mount) { - monitor->volumes = g_list_prepend (monitor->volumes, volume); - g_signal_emit_by_name (monitor, "volume_mounted", volume); + monitor->mounts = g_list_prepend (monitor->mounts, mount); + g_signal_emit_by_name (monitor, "mount_added", mount); } } diff --git a/gio/gunixvolumemonitor.h b/gio/gunixvolumemonitor.h index ecaffd598..1732c147d 100644 --- a/gio/gunixvolumemonitor.h +++ b/gio/gunixvolumemonitor.h @@ -18,6 +18,7 @@ * Boston, MA 02111-1307, USA. * * Author: Alexander Larsson + * David Zeuthen */ #ifndef __G_UNIX_VOLUME_MONITOR_H__ @@ -38,8 +39,8 @@ typedef struct _GUnixVolumeMonitor GUnixVolumeMonitor; typedef struct _GUnixVolumeMonitorClass GUnixVolumeMonitorClass; /* Forward definitions */ +typedef struct _GUnixMount GUnixMount; typedef struct _GUnixVolume GUnixVolume; -typedef struct _GUnixDrive GUnixDrive; struct _GUnixVolumeMonitorClass { GNativeVolumeMonitorClass parent_class; @@ -48,9 +49,9 @@ struct _GUnixVolumeMonitorClass { GType _g_unix_volume_monitor_get_type (void) G_GNUC_CONST; -GVolumeMonitor *_g_unix_volume_monitor_new (void); -GUnixDrive * _g_unix_volume_monitor_lookup_drive_for_mountpoint (GUnixVolumeMonitor *monitor, - const char *mountpoint); +GVolumeMonitor * _g_unix_volume_monitor_new (void); +GUnixVolume * _g_unix_volume_monitor_lookup_volume_for_mount_path (GUnixVolumeMonitor *monitor, + const char *mount_path); G_END_DECLS diff --git a/gio/gvolume.c b/gio/gvolume.c index 2b0bb1204..25c07ffba 100644 --- a/gio/gvolume.c +++ b/gio/gvolume.c @@ -18,46 +18,42 @@ * Boston, MA 02111-1307, USA. * * Author: Alexander Larsson + * David Zeuthen */ #include +#include "gmount.h" #include "gvolume.h" -#include "gvolumeprivate.h" #include "gsimpleasyncresult.h" #include "glibintl.h" #include "gioalias.h" /** - * SECTION:gvolume - * @short_description: mounted volume management + * SECTION:volume + * @short_description: volume management * - * Class for managing mounted volumes. - * - * Unmounting volumes is an asynchronous operation. For more information about - * asynchronous operations, see #GAsyncReady and #GSimpleAsyncReady. To unmount a volume, - * first call g_volume_unmount() with (at least) the volume and a #GAsyncReadyCallback. - * The callback will be fired when the operation has resolved (either with success or failure), - * and a #GAsyncReady structure will be passed to the callback. - * That callback should then call g_volume_unmount_finish() with - * the volume and the #GAsyncReady data to see if the operation was completed successfully. - * If an @error is present when g_volume_unmount_finish() is called, then it will - * be filled with any error information. - * - * Ejecting volumes is also an asynchronous operation. - * To eject a volume, call g_volume_eject() with (at least) the volume to eject - * and a #GAsyncReadyCallback. The callback will be fired when the eject operation - * has resolved (either with success or failure), and a #GAsyncReady structure will - * be passed to the callback. That callback should then call g_volume_eject_finish() - * with the volume and the #GAsyncReady data to determine if the operation was completed - * successfully. If an @error is present when g_volume_eject_finish() is called, then - * it will be filled with any error information. + * The #GVolume interface represents user-visible objects that can be + * mounted. Note, when porting from GnomeVFS, #GVolume is the moral + * equivalent of #GnomeVFSDrive. * + * Mounting a #GVolume instance is an asynchronous operation. For more + * information about asynchronous operations, see #GAsyncReady and + * #GSimpleAsyncReady. To mount a #GVolume, first call + * g_volume_mount() with (at least) the #GVolume instane, a + * #GMountOperation object and a #GAsyncReadyCallback. The callback + * will be fired when the operation has resolved (either with success + * or failure), and a #GAsyncReady structure will be passed to the + * callback. That callback should then call g_volume_mount_finish() + * with the #GVolume instance and the #GAsyncReady data to see if the + * operation was completed successfully. If an @error is present when + * g_volume_mount_finish() is called, then it will be filled with any + * error information. **/ static void g_volume_base_init (gpointer g_class); static void g_volume_class_init (gpointer g_class, - gpointer class_data); + gpointer class_data); GType g_volume_get_type (void) @@ -91,7 +87,7 @@ g_volume_get_type (void) static void g_volume_class_init (gpointer g_class, - gpointer class_data) + gpointer class_data) { } @@ -119,26 +115,6 @@ g_volume_base_init (gpointer g_class) } } -/** - * g_volume_get_root: - * @volume: a #GVolume. - * - * Gets the root directory on @volume. - * - * Returns: a #GFile. - **/ -GFile * -g_volume_get_root (GVolume *volume) -{ - GVolumeIface *iface; - - g_return_val_if_fail (G_IS_VOLUME (volume), NULL); - - iface = G_VOLUME_GET_IFACE (volume); - - return (* iface->get_root) (volume); -} - /** * g_volume_get_name: * @volume: a #GVolume. @@ -186,7 +162,7 @@ g_volume_get_icon (GVolume *volume) * * Gets the drive for the @volume. * - * Returns: a #GDrive. + * Returns: a #GDrive or %NULL if @volume is not associated with a drive. **/ GDrive * g_volume_get_drive (GVolume *volume) @@ -201,15 +177,36 @@ g_volume_get_drive (GVolume *volume) } /** - * g_volume_can_unmount: + * g_volume_get_mount: * @volume: a #GVolume. * - * Checks if @volume can be mounted. + * Gets the mount for the @volume. * - * Returns: %TRUE if the @volume can be unmounted. + * Returns: a #GMount or %NULL if @volume isn't mounted. + **/ +GMount * +g_volume_get_mount (GVolume *volume) +{ + GVolumeIface *iface; + + g_return_val_if_fail (G_IS_VOLUME (volume), NULL); + + iface = G_VOLUME_GET_IFACE (volume); + + return (* iface->get_mount) (volume); +} + + +/** + * g_volume_can_mount: + * @volume: a #GVolume. + * + * Checks if a volume can be mounted. + * + * Returns: %TRUE if the @volume can be mounted. %FALSE otherwise. **/ gboolean -g_volume_can_unmount (GVolume *volume) +g_volume_can_mount (GVolume *volume) { GVolumeIface *iface; @@ -217,81 +214,62 @@ g_volume_can_unmount (GVolume *volume) iface = G_VOLUME_GET_IFACE (volume); - return (* iface->can_unmount) (volume); + if (iface->can_mount == NULL) + return FALSE; + + return (* iface->can_mount) (volume); } /** - * g_volume_can_eject: - * @volume: a #GVolume. - * - * Checks if @volume can be ejected. - * - * Returns: %TRUE if the @volume can be ejected. - **/ -gboolean -g_volume_can_eject (GVolume *volume) -{ - GVolumeIface *iface; - - g_return_val_if_fail (G_IS_VOLUME (volume), FALSE); - - iface = G_VOLUME_GET_IFACE (volume); - - return (* iface->can_eject) (volume); -} - -/** - * g_volume_unmount: + * g_volume_mount: * @volume: a #GVolume. + * @mount_operation: a #GMountOperation. * @cancellable: optional #GCancellable object, %NULL to ignore. * @callback: a #GAsyncReadyCallback. - * @user_data: user data passed to @callback. + * @user_data: a #gpointer. * - * Unmounts a volume. This is an asynchronous operation, and is - * finished by calling g_volume_unmount_finish() with the @volume - * and #GAsyncResults data returned in the @callback. + * Mounts a volume. **/ void -g_volume_unmount (GVolume *volume, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) +g_volume_mount (GVolume *volume, + GMountOperation *mount_operation, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { GVolumeIface *iface; g_return_if_fail (G_IS_VOLUME (volume)); - + g_return_if_fail (G_IS_MOUNT_OPERATION (mount_operation)); + iface = G_VOLUME_GET_IFACE (volume); - if (iface->unmount == NULL) + if (iface->mount_fn == NULL) { - g_simple_async_report_error_in_idle (G_OBJECT (volume), - callback, user_data, + g_simple_async_report_error_in_idle (G_OBJECT (volume), callback, user_data, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, - _("volume doesn't implement unmount")); + _("volume doesn't implement mount")); return; } - (* iface->unmount) (volume, cancellable, callback, user_data); + (* iface->mount_fn) (volume, mount_operation, cancellable, callback, user_data); } /** - * g_volume_unmount_finish: - * @volume: a #GVolume. + * g_volume_mount_finish: + * @volume: pointer to a #GVolume. * @result: a #GAsyncResult. - * @error: a #GError location to store the error occuring, or %NULL to - * ignore. + * @error: a #GError. * - * Finishes unmounting a volume. If any errors occured during the operation, - * @error will be set to contain the errors and %FALSE will be returned. + * Finishes mounting a volume. * - * Returns: %TRUE if the volume was successfully unmounted. %FALSE otherwise. + * Returns: %TRUE, %FALSE if operation failed. **/ gboolean -g_volume_unmount_finish (GVolume *volume, - GAsyncResult *result, - GError **error) +g_volume_mount_finish (GVolume *volume, + GAsyncResult *result, + GError **error) { GVolumeIface *iface; @@ -306,76 +284,7 @@ g_volume_unmount_finish (GVolume *volume, } iface = G_VOLUME_GET_IFACE (volume); - return (* iface->unmount_finish) (volume, result, error); -} - -/** - * g_volume_eject: - * @volume: a #GVolume. - * @cancellable: optional #GCancellable object, %NULL to ignore. - * @callback: a #GAsyncReadyCallback. - * @user_data: user data passed to @callback. - * - * Ejects a volume. This is an asynchronous operation, and is - * finished by calling g_volume_eject_finish() from the @callback - * with the @volume and #GAsyncResults returned in the callback. - **/ -void -g_volume_eject (GVolume *volume, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GVolumeIface *iface; - - g_return_if_fail (G_IS_VOLUME (volume)); - - iface = G_VOLUME_GET_IFACE (volume); - - if (iface->eject == NULL) - { - g_simple_async_report_error_in_idle (G_OBJECT (volume), - callback, user_data, - G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, - _("volume doesn't implement eject")); - - return; - } - - (* iface->eject) (volume, cancellable, callback, user_data); -} - -/** - * g_volume_eject_finish: - * @volume: a #GVolume. - * @result: a #GAsyncResult. - * @error: a #GError location to store the error occuring, or %NULL to - * ignore. - * - * Finishes ejecting the volume. If any errors occured during the operation, - * @error will be set to contain the errors and %FALSE will be returned. - * - * Returns: %TRUE if the volume was successfully ejected. %FALSE otherwise. - **/ -gboolean -g_volume_eject_finish (GVolume *volume, - GAsyncResult *result, - GError **error) -{ - GVolumeIface *iface; - - g_return_val_if_fail (G_IS_VOLUME (volume), FALSE); - g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE); - - if (G_IS_SIMPLE_ASYNC_RESULT (result)) - { - GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result); - if (g_simple_async_result_propagate_error (simple, error)) - return FALSE; - } - - iface = G_VOLUME_GET_IFACE (volume); - return (* iface->eject_finish) (volume, result, error); + return (* iface->mount_finish) (volume, result, error); } #define __G_VOLUME_C__ diff --git a/gio/gvolume.h b/gio/gvolume.h index d45c901fb..c73241be3 100644 --- a/gio/gvolume.h +++ b/gio/gvolume.h @@ -18,6 +18,7 @@ * Boston, MA 02111-1307, USA. * * Author: Alexander Larsson + * David Zeuthen */ #ifndef __G_VOLUME_H__ @@ -25,6 +26,7 @@ #include #include +#include G_BEGIN_DECLS @@ -33,32 +35,22 @@ G_BEGIN_DECLS #define G_IS_VOLUME(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), G_TYPE_VOLUME)) #define G_VOLUME_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), G_TYPE_VOLUME, GVolumeIface)) -/* GVolume typedef is in gfile.h due to include order issues */ -/** - * GDrive: - * - * Opaque drive object. - **/ -typedef struct _GDrive GDrive; /* Dummy typedef */ -typedef struct _GVolumeIface GVolumeIface; - /** * GVolumeIface: * @g_iface: The parent interface. * @changed: Changed signal that is emitted when the volume's state has changed. - * @get_root: Gets a #GFile to the root directory of the #GVolume. * @get_name: Gets a string containing the name of the #GVolume. * @get_icon: Gets a #GIcon for the #GVolume. - * @get_drive: Gets a #GDrive the volume is located on. - * @can_unmount: Checks if a #GVolume can be unmounted. - * @can_eject: Checks if a #GVolume can be ejected. - * @unmount: Starts unmounting a #GVolume. - * @unmount_finish: Finishes an unmounting operation. - * @eject: Starts ejecting a #GVolume. - * @eject_finish: Finishes an eject operation. + * @get_drive: Gets a #GDrive the volume is located on. Returns %NULL if the #GVolume is not associated with a #GDrive. + * @get_mount: Gets a #GMount representing the mounted volume. Returns %NULL if the #GVolume is not mounted. + * @can_mount: Returns %TRUE if the #GVolume can be mounted. + * @mount: Mounts a given #GVolume. + * @mount_finish: Finishes a mount operation. * - * Interface for implementing operations for mounted volumes. + * Interface for implementing operations for mountable volumes. **/ +typedef struct _GVolumeIface GVolumeIface; + struct _GVolumeIface { GTypeInterface g_iface; @@ -69,50 +61,47 @@ struct _GVolumeIface /* Virtual Table */ - GFile * (*get_root) (GVolume *volume); - char * (*get_name) (GVolume *volume); - GIcon * (*get_icon) (GVolume *volume); - GDrive * (*get_drive) (GVolume *volume); - gboolean (*can_unmount) (GVolume *volume); - gboolean (*can_eject) (GVolume *volume); - void (*unmount) (GVolume *volume, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - gboolean (*unmount_finish) (GVolume *volume, - GAsyncResult *result, - GError **error); - void (*eject) (GVolume *volume, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - gboolean (*eject_finish) (GVolume *volume, - GAsyncResult *result, - GError **error); + char * (*get_name) (GVolume *volume); + GIcon * (*get_icon) (GVolume *volume); + GDrive * (*get_drive) (GVolume *volume); + GMount * (*get_mount) (GVolume *volume); + gboolean (*can_mount) (GVolume *volume); + void (*mount_fn) (GVolume *volume, + GMountOperation *mount_operation, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + gboolean (*mount_finish) (GVolume *volume, + GAsyncResult *result, + GError **error); + + /*< private >*/ + /* Padding for future expansion */ + void (*_g_reserved1) (void); + void (*_g_reserved2) (void); + void (*_g_reserved3) (void); + void (*_g_reserved4) (void); + void (*_g_reserved5) (void); + void (*_g_reserved6) (void); + void (*_g_reserved7) (void); + void (*_g_reserved8) (void); }; -GType g_volume_get_type (void) G_GNUC_CONST; +GType g_volume_get_type (void) G_GNUC_CONST; -GFile *g_volume_get_root (GVolume *volume); -char * g_volume_get_name (GVolume *volume); -GIcon * g_volume_get_icon (GVolume *volume); -GDrive * g_volume_get_drive (GVolume *volume); -gboolean g_volume_can_unmount (GVolume *volume); -gboolean g_volume_can_eject (GVolume *volume); -void g_volume_unmount (GVolume *volume, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); -gboolean g_volume_unmount_finish (GVolume *volume, - GAsyncResult *result, - GError **error); -void g_volume_eject (GVolume *volume, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); -gboolean g_volume_eject_finish (GVolume *volume, - GAsyncResult *result, - GError **error); +char * g_volume_get_name (GVolume *volume); +GIcon * g_volume_get_icon (GVolume *volume); +GDrive * g_volume_get_drive (GVolume *volume); +GMount * g_volume_get_mount (GVolume *volume); +gboolean g_volume_can_mount (GVolume *volume); +void g_volume_mount (GVolume *volume, + GMountOperation *mount_operation, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean g_volume_mount_finish (GVolume *volume, + GAsyncResult *result, + GError **error); G_END_DECLS diff --git a/gio/gvolumemonitor.c b/gio/gvolumemonitor.c index d4d59a512..36319aa36 100644 --- a/gio/gvolumemonitor.c +++ b/gio/gvolumemonitor.c @@ -18,6 +18,7 @@ * Boston, MA 02111-1307, USA. * * Author: Alexander Larsson + * David Zeuthen */ #include @@ -37,11 +38,16 @@ G_DEFINE_TYPE (GVolumeMonitor, g_volume_monitor, G_TYPE_OBJECT); enum { - VOLUME_MOUNTED, - VOLUME_PRE_UNMOUNT, - VOLUME_UNMOUNTED, + VOLUME_ADDED, + VOLUME_REMOVED, + VOLUME_CHANGED, + MOUNT_ADDED, + MOUNT_REMOVED, + MOUNT_PRE_UNMOUNT, + MOUNT_CHANGED, DRIVE_CONNECTED, DRIVE_DISCONNECTED, + DRIVE_CHANGED, LAST_SIGNAL }; @@ -67,47 +73,110 @@ g_volume_monitor_class_init (GVolumeMonitorClass *klass) gobject_class->finalize = g_volume_monitor_finalize; /** - * GVolumeMonitor::volume-mounted: + * GVolumeMonitor::volume-added: * @volume_monitor: The volume monitor emitting the signal. - * @volume: the volume that was mounted. - * - * Emitted when a volume is mounted. - **/ - signals[VOLUME_MOUNTED] = g_signal_new (I_("volume_mounted"), - G_TYPE_VOLUME_MONITOR, - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GVolumeMonitorClass, volume_mounted), - NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, G_TYPE_VOLUME); - /** - * GVolumeMonitor::volume-pre-unmount: - * @volume_monitor: The volume monitor emitting the signal. - * @volume: the volume that is being unmounted. - * - * Emitted when a volume is about to be unmounted. - **/ - signals[VOLUME_PRE_UNMOUNT] = g_signal_new (I_("volume_pre_unmount"), - G_TYPE_VOLUME_MONITOR, - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GVolumeMonitorClass, volume_pre_unmount), - NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, G_TYPE_VOLUME); - /** - * GVolumeMonitor::volume-unmounted: - * @volume_monitor: The volume monitor emitting the signal. - * @volume: the volume that was unmounted. + * @volume: a #GVolume that was added. * - * Emitted when a volume is unmounted. + * Emitted when a mountable volume is added to the system. + **/ + signals[VOLUME_ADDED] = g_signal_new (I_("volume_added"), + G_TYPE_VOLUME_MONITOR, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GVolumeMonitorClass, volume_added), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, G_TYPE_VOLUME); + + /** + * GVolumeMonitor::volume-removed: + * @volume_monitor: The volume monitor emitting the signal. + * @volume: a #GVolume that was removed. + * + * Emitted when a mountable volume is removed from the system. **/ - signals[VOLUME_UNMOUNTED] = g_signal_new (I_("volume_unmounted"), - G_TYPE_VOLUME_MONITOR, - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GVolumeMonitorClass, volume_unmounted), - NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, G_TYPE_VOLUME); + signals[VOLUME_REMOVED] = g_signal_new (I_("volume_removed"), + G_TYPE_VOLUME_MONITOR, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GVolumeMonitorClass, volume_removed), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, G_TYPE_VOLUME); + + /** + * GVolumeMonitor::volume-changed: + * @volume_monitor: The volume monitor emitting the signal. + * @volume: a #GVolume that changed. + * + * Emitted when mountable volume is changed. + **/ + signals[VOLUME_CHANGED] = g_signal_new (I_("volume_changed"), + G_TYPE_VOLUME_MONITOR, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GVolumeMonitorClass, volume_changed), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, G_TYPE_VOLUME); + + /** + * GVolumeMonitor::mount-added: + * @volume_monitor: The volume monitor emitting the signal. + * @mount: a #GMount that was added. + * + * Emitted when a mount is added. + **/ + signals[MOUNT_ADDED] = g_signal_new (I_("mount_added"), + G_TYPE_VOLUME_MONITOR, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GVolumeMonitorClass, mount_added), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, G_TYPE_MOUNT); + + /** + * GVolumeMonitor::mount-removed: + * @volume_monitor: The volume monitor emitting the signal. + * @mount: a #GMount that was removed. + * + * Emitted when a mount is removed. + **/ + signals[MOUNT_REMOVED] = g_signal_new (I_("mount_removed"), + G_TYPE_VOLUME_MONITOR, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GVolumeMonitorClass, mount_removed), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, G_TYPE_MOUNT); + + /** + * GVolumeMonitor::mount-pre-unmount: + * @volume_monitor: The volume monitor emitting the signal. + * @mount: a #GMount that is being unmounted. + * + * Emitted when a mount is about to be removed. + **/ + signals[MOUNT_PRE_UNMOUNT] = g_signal_new (I_("mount_pre_unmount"), + G_TYPE_VOLUME_MONITOR, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GVolumeMonitorClass, mount_pre_unmount), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, G_TYPE_MOUNT); + + /** + * GVolumeMonitor::mount-changed: + * @volume_monitor: The volume monitor emitting the signal. + * @mount: a #GMount that changed. + * + * Emitted when a mount changes. + **/ + signals[MOUNT_CHANGED] = g_signal_new (I_("mount_changed"), + G_TYPE_VOLUME_MONITOR, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GVolumeMonitorClass, mount_changed), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, G_TYPE_MOUNT); + /** * GVolumeMonitor::drive-connected: * @volume_monitor: The volume monitor emitting the signal. @@ -137,6 +206,22 @@ g_volume_monitor_class_init (GVolumeMonitorClass *klass) NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, G_TYPE_DRIVE); + + /** + * GVolumeMonitor::drive-changed: + * @volume_monitor: The volume monitor emitting the signal. + * @drive: the drive that changed + * + * Emitted when a drive changes. + **/ + signals[DRIVE_CHANGED] = g_signal_new (I_("drive_changed"), + G_TYPE_VOLUME_MONITOR, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GVolumeMonitorClass, drive_changed), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, G_TYPE_DRIVE); + } static void @@ -144,31 +229,12 @@ g_volume_monitor_init (GVolumeMonitor *monitor) { } -/** - * g_volume_monitor_get_mounted_volumes: - * @volume_monitor: a #GVolumeMonitor. - * - * Gets a list of volumes mounted on the computer. - * - * Returns: a #GList of mounted #GVolumes. - **/ -GList * -g_volume_monitor_get_mounted_volumes (GVolumeMonitor *volume_monitor) -{ - GVolumeMonitorClass *class; - - g_return_val_if_fail (G_IS_VOLUME_MONITOR (volume_monitor), NULL); - - class = G_VOLUME_MONITOR_GET_CLASS (volume_monitor); - - return class->get_mounted_volumes (volume_monitor); -} /** - * g_volume_monitor_get_connected_drives: + * g_volume_monitor_get_drives: * @volume_monitor: a #GVolumeMonitor. * - * Gets a list of drives connected to the computer. + * Gets a list of drives connected to the system. * * Returns: a #GList of connected #GDrives. **/ @@ -184,5 +250,45 @@ g_volume_monitor_get_connected_drives (GVolumeMonitor *volume_monitor) return class->get_connected_drives (volume_monitor); } +/** + * g_volume_monitor_get_volumes: + * @volume_monitor: a #GVolumeMonitor. + * + * Gets a list of the volumes on the system. + * + * Returns: a #GList of #GVolume. + **/ +GList * +g_volume_monitor_get_volumes (GVolumeMonitor *volume_monitor) +{ + GVolumeMonitorClass *class; + + g_return_val_if_fail (G_IS_VOLUME_MONITOR (volume_monitor), NULL); + + class = G_VOLUME_MONITOR_GET_CLASS (volume_monitor); + + return class->get_volumes (volume_monitor); +} + +/** + * g_volume_monitor_get_mounts: + * @volume_monitor: a #GVolumeMonitor. + * + * Gets a list of the mounts on the system. + * + * Returns: a #GList of #GMount. + **/ +GList * +g_volume_monitor_get_mounts (GVolumeMonitor *volume_monitor) +{ + GVolumeMonitorClass *class; + + g_return_val_if_fail (G_IS_VOLUME_MONITOR (volume_monitor), NULL); + + class = G_VOLUME_MONITOR_GET_CLASS (volume_monitor); + + return class->get_mounts (volume_monitor); +} + #define __G_VOLUME_MONITOR_C__ #include "gioaliasdef.c" diff --git a/gio/gvolumemonitor.h b/gio/gvolumemonitor.h index 63892e925..46decc5e2 100644 --- a/gio/gvolumemonitor.h +++ b/gio/gvolumemonitor.h @@ -18,12 +18,14 @@ * Boston, MA 02111-1307, USA. * * Author: Alexander Larsson + * David Zeuthen */ #ifndef __G_VOLUME_MONITOR_H__ #define __G_VOLUME_MONITOR_H__ #include +#include #include #include @@ -57,21 +59,34 @@ struct _GVolumeMonitorClass { /*< public >*/ /* signals */ - void (* volume_mounted) (GVolumeMonitor *volume_monitor, - GVolume *volume); - void (* volume_pre_unmount) (GVolumeMonitor *volume_monitor, - GVolume *volume); - void (* volume_unmounted) (GVolumeMonitor *volume_monitor, - GVolume *volume); - void (* drive_connected) (GVolumeMonitor *volume_monitor, + void (* volume_added) (GVolumeMonitor *volume_monitor, + GVolume *volume); + void (* volume_removed) (GVolumeMonitor *volume_monitor, + GVolume *volume); + void (* volume_changed) (GVolumeMonitor *volume_monitor, + GVolume *volume); + + void (* mount_added) (GVolumeMonitor *volume_monitor, + GMount *mount); + void (* mount_removed) (GVolumeMonitor *volume_monitor, + GMount *mount); + void (* mount_pre_unmount) (GVolumeMonitor *volume_monitor, + GMount *mount); + void (* mount_changed) (GVolumeMonitor *volume_monitor, + GMount *mount); + + void (* drive_connected) (GVolumeMonitor *volume_monitor, GDrive *drive); - void (* drive_disconnected) (GVolumeMonitor *volume_monitor, + void (* drive_disconnected) (GVolumeMonitor *volume_monitor, + GDrive *drive); + void (* drive_changed) (GVolumeMonitor *volume_monitor, GDrive *drive); /* Vtable */ - GList * (*get_mounted_volumes) (GVolumeMonitor *volume_monitor); - GList * (*get_connected_drives) (GVolumeMonitor *volume_monitor); + GList * (*get_connected_drives) (GVolumeMonitor *volume_monitor); + GList * (*get_volumes) (GVolumeMonitor *volume_monitor); + GList * (*get_mounts) (GVolumeMonitor *volume_monitor); /*< private >*/ /* Padding for future expansion */ @@ -87,9 +102,10 @@ struct _GVolumeMonitorClass { GType g_volume_monitor_get_type (void) G_GNUC_CONST; -GVolumeMonitor *g_volume_monitor_get (void); -GList * g_volume_monitor_get_mounted_volumes (GVolumeMonitor *volume_monitor); +GVolumeMonitor *g_volume_monitor_get (void); GList * g_volume_monitor_get_connected_drives (GVolumeMonitor *volume_monitor); +GList * g_volume_monitor_get_volumes (GVolumeMonitor *volume_monitor); +GList * g_volume_monitor_get_mounts (GVolumeMonitor *volume_monitor); G_END_DECLS