Merge branch 'more-async-gfile' into 'main'

gfile (and GAppInfo): Add some missing async APIs and ensure async calls always use them

See merge request GNOME/glib!2717
This commit is contained in:
Philip Withnall 2022-06-23 11:49:55 +00:00
commit 5655af6ada
13 changed files with 2730 additions and 129 deletions

View File

@ -84,6 +84,10 @@ g_file_new_for_uri
g_file_new_for_commandline_arg
g_file_new_for_commandline_arg_and_cwd
g_file_new_tmp
g_file_new_tmp_async
g_file_new_tmp_finish
g_file_new_tmp_dir_async
g_file_new_tmp_dir_finish
g_file_parse_name
g_file_new_build_filename
g_file_dup
@ -156,6 +160,8 @@ g_file_make_directory_async
g_file_make_directory_finish
g_file_make_directory_with_parents
g_file_make_symbolic_link
g_file_make_symbolic_link_async
g_file_make_symbolic_link_finish
g_file_query_settable_attributes
g_file_query_writable_namespaces
g_file_set_attribute
@ -1371,6 +1377,7 @@ g_io_scheduler_job_send_to_mainloop_async
G_IO_ERROR
GIOErrorEnum
g_io_error_from_errno
g_io_error_from_file_error
g_io_error_from_win32_error
<SUBSECTION Standard>
G_TYPE_IO_ERROR_ENUM
@ -1435,7 +1442,11 @@ g_app_info_get_supported_types
g_app_info_get_all
g_app_info_get_all_for_type
g_app_info_get_default_for_type
g_app_info_get_default_for_type_async
g_app_info_get_default_for_type_finish
g_app_info_get_default_for_uri_scheme
g_app_info_get_default_for_uri_scheme_async
g_app_info_get_default_for_uri_scheme_finish
g_app_info_get_fallback_for_type
g_app_info_get_recommended_for_type
g_app_info_launch_default_for_uri

View File

@ -778,6 +778,188 @@ g_app_info_should_show (GAppInfo *appinfo)
return (* iface->should_show) (appinfo);
}
typedef struct {
char *content_type;
gboolean must_support_uris;
} DefaultForTypeData;
static void
default_for_type_data_free (DefaultForTypeData *data)
{
g_free (data->content_type);
g_free (data);
}
static void
get_default_for_type_thread (GTask *task,
gpointer object,
gpointer task_data,
GCancellable *cancellable)
{
DefaultForTypeData *data = task_data;
GAppInfo *info;
info = g_app_info_get_default_for_type (data->content_type,
data->must_support_uris);
if (!info)
{
g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
_("Failed to find default application for "
"content type %s"), data->content_type);
return;
}
g_task_return_pointer (task, g_steal_pointer (&info), g_object_unref);
}
/**
* g_app_info_get_default_for_type_async:
* @content_type: the content type to find a #GAppInfo for
* @must_support_uris: if %TRUE, the #GAppInfo is expected to
* support URIs
* @cancellable: optional #GCancellable object, %NULL to ignore
* @callback: (nullable): a #GAsyncReadyCallback to call when the request is done
* @user_data: (nullable): data to pass to @callback
*
* Asynchronously gets the default #GAppInfo for a given content type.
*
* Since: 2.74
*/
void
g_app_info_get_default_for_type_async (const char *content_type,
gboolean must_support_uris,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GTask *task;
DefaultForTypeData *data;
g_return_if_fail (content_type != NULL && *content_type != '\0');
g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
data = g_new0 (DefaultForTypeData, 1);
data->content_type = g_strdup (content_type);
data->must_support_uris = must_support_uris;
task = g_task_new (NULL, cancellable, callback, user_data);
g_task_set_source_tag (task, g_app_info_get_default_for_type_async);
g_task_set_task_data (task, data, (GDestroyNotify) default_for_type_data_free);
g_task_set_check_cancellable (task, TRUE);
g_task_run_in_thread (task, get_default_for_type_thread);
g_object_unref (task);
}
static void
get_default_for_scheme_thread (GTask *task,
gpointer object,
gpointer task_data,
GCancellable *cancellable)
{
const char *uri_scheme = task_data;
GAppInfo *info;
info = g_app_info_get_default_for_uri_scheme (uri_scheme);
if (!info)
{
g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
_("Failed to find default application for "
"URI Scheme %s"), uri_scheme);
return;
}
g_task_return_pointer (task, g_steal_pointer (&info), g_object_unref);
}
/**
* g_app_info_get_default_for_uri_scheme_async:
* @uri_scheme: a string containing a URI scheme.
* @cancellable: optional #GCancellable object, %NULL to ignore
* @callback: (nullable): a #GAsyncReadyCallback to call when the request is done
* @user_data: (nullable): data to pass to @callback
*
* Asynchronously gets the default application for handling URIs with
* the given URI scheme. A URI scheme is the initial part
* of the URI, up to but not including the ':', e.g. "http",
* "ftp" or "sip".
*
* Since: 2.74
*/
void
g_app_info_get_default_for_uri_scheme_async (const char *uri_scheme,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GTask *task;
g_return_if_fail (uri_scheme != NULL && *uri_scheme != '\0');
g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
task = g_task_new (NULL, cancellable, callback, user_data);
g_task_set_source_tag (task, g_app_info_get_default_for_uri_scheme_async);
g_task_set_task_data (task, g_strdup (uri_scheme), g_free);
g_task_set_check_cancellable (task, TRUE);
g_task_run_in_thread (task, get_default_for_scheme_thread);
g_object_unref (task);
}
/**
* g_app_info_get_default_for_uri_scheme_finish:
* @result: a #GAsyncResult
* @error: (nullable): a #GError
*
* Finishes a default #GAppInfo lookup started by
* g_app_info_get_default_for_uri_scheme_async().
*
* If no #GAppInfo is found, then @error will be set to %G_IO_ERROR_NOT_FOUND.
*
* Returns: (transfer full): #GAppInfo for given @uri_scheme or
* %NULL on error.
*
* Since: 2.74
*/
GAppInfo *
g_app_info_get_default_for_uri_scheme_finish (GAsyncResult *result,
GError **error)
{
g_return_val_if_fail (g_task_is_valid (result, NULL), NULL);
g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) ==
g_app_info_get_default_for_uri_scheme_async, NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
return g_task_propagate_pointer (G_TASK (result), error);
}
/**
* g_app_info_get_default_for_type_finish:
* @result: a #GAsyncResult
* @error: (nullable): a #GError
*
* Finishes a default #GAppInfo lookup started by
* g_app_info_get_default_for_type_async().
*
* If no #GAppInfo is found, then @error will be set to %G_IO_ERROR_NOT_FOUND.
*
* Returns: (transfer full): #GAppInfo for given @content_type or
* %NULL on error.
*
* Since: 2.74
*/
GAppInfo *
g_app_info_get_default_for_type_finish (GAsyncResult *result,
GError **error)
{
g_return_val_if_fail (g_task_is_valid (result, NULL), NULL);
g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) ==
g_app_info_get_default_for_type_async, NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
return g_task_propagate_pointer (G_TASK (result), error);
}
/**
* g_app_info_launch_default_for_uri:
* @uri: the uri to show
@ -966,6 +1148,46 @@ launch_default_for_uri_default_handler_cb (GObject *object,
launch_default_for_uri_portal_open_uri (g_steal_pointer (&task), g_steal_pointer (&error));
}
static void
launch_default_app_for_default_handler (GTask *task)
{
GFile *file;
GCancellable *cancellable;
LaunchDefaultForUriData *data;
data = g_task_get_task_data (task);
cancellable = g_task_get_cancellable (task);
file = g_file_new_for_uri (data->uri);
g_file_query_default_handler_async (file,
G_PRIORITY_DEFAULT,
cancellable,
launch_default_for_uri_default_handler_cb,
g_steal_pointer (&task));
g_object_unref (file);
}
static void
launch_default_app_for_uri_cb (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
GTask *task = G_TASK (user_data);
GAppInfo *app_info;
app_info = g_app_info_get_default_for_uri_scheme_finish (result, NULL);
if (!app_info)
{
launch_default_app_for_default_handler (g_steal_pointer (&task));
}
else
{
launch_default_for_uri_launch_uris (g_steal_pointer (&task),
g_steal_pointer (&app_info));
}
}
/**
* g_app_info_launch_default_for_uri_async:
* @uri: the uri to show
@ -996,7 +1218,6 @@ g_app_info_launch_default_for_uri_async (const char *uri,
{
GTask *task;
char *uri_scheme;
GAppInfo *app_info = NULL;
LaunchDefaultForUriData *data;
g_return_if_fail (uri != NULL);
@ -1015,24 +1236,18 @@ g_app_info_launch_default_for_uri_async (const char *uri,
*/
uri_scheme = g_uri_parse_scheme (uri);
if (uri_scheme && uri_scheme[0] != '\0')
/* FIXME: The following still uses blocking calls. */
app_info = g_app_info_get_default_for_uri_scheme (uri_scheme);
g_free (uri_scheme);
if (!app_info)
{
GFile *file;
file = g_file_new_for_uri (uri);
g_file_query_default_handler_async (file,
G_PRIORITY_DEFAULT,
cancellable,
launch_default_for_uri_default_handler_cb,
g_steal_pointer (&task));
g_object_unref (file);
g_app_info_get_default_for_uri_scheme_async (uri_scheme,
cancellable,
launch_default_app_for_uri_cb,
g_steal_pointer (&task));
}
else
launch_default_for_uri_launch_uris (g_steal_pointer (&task), g_steal_pointer (&app_info));
{
launch_default_app_for_default_handler (g_steal_pointer (&task));
}
g_free (uri_scheme);
}
/**

View File

@ -246,9 +246,27 @@ void g_app_info_reset_type_associations (const char *content_type);
GLIB_AVAILABLE_IN_ALL
GAppInfo *g_app_info_get_default_for_type (const char *content_type,
gboolean must_support_uris);
GLIB_AVAILABLE_IN_2_74
void g_app_info_get_default_for_type_async (const char *content_type,
gboolean must_support_uris,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
GLIB_AVAILABLE_IN_2_74
GAppInfo *g_app_info_get_default_for_type_finish (GAsyncResult *result,
GError **error);
GLIB_AVAILABLE_IN_ALL
GAppInfo *g_app_info_get_default_for_uri_scheme (const char *uri_scheme);
GLIB_AVAILABLE_IN_2_74
void g_app_info_get_default_for_uri_scheme_async (const char *uri_scheme,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
GLIB_AVAILABLE_IN_2_74
GAppInfo *g_app_info_get_default_for_uri_scheme_finish (GAsyncResult *result,
GError **error);
GLIB_AVAILABLE_IN_ALL
gboolean g_app_info_launch_default_for_uri (const char *uri,
GAppLaunchContext *context,

View File

@ -3349,11 +3349,16 @@ launch_uris_bus_get_cb (GObject *object,
g_task_return_error (task, g_steal_pointer (&error));
g_object_unref (task);
}
else
else if (session_bus)
g_dbus_connection_flush (session_bus,
cancellable,
launch_uris_flush_cb,
g_steal_pointer (&task));
else
{
g_task_return_boolean (task, TRUE);
g_clear_object (&task);
}
}
g_clear_object (&session_bus);
@ -4626,6 +4631,8 @@ g_app_info_get_default_for_uri_scheme (const char *uri_scheme)
GAppInfo *app_info;
char *content_type, *scheme_down;
g_return_val_if_fail (uri_scheme != NULL && *uri_scheme != '\0', NULL);
scheme_down = g_ascii_strdown (uri_scheme, -1);
content_type = g_strdup_printf ("x-scheme-handler/%s", scheme_down);
g_free (scheme_down);

View File

@ -96,6 +96,8 @@
* - g_file_new_for_uri() if you have a URI.
* - g_file_new_for_commandline_arg() for a command line argument.
* - g_file_new_tmp() to create a temporary file from a template.
* - g_file_new_tmp_async() to asynchronously create a temporary file.
* - g_file_new_tmp_dir_async() to asynchronously create a temporary directory.
* - g_file_parse_name() from a UTF-8 string gotten from g_file_get_parse_name().
* - g_file_new_build_filename() to create a file from path elements.
*
@ -269,6 +271,15 @@ static void g_file_real_make_directory_async (GFile
static gboolean g_file_real_make_directory_finish (GFile *file,
GAsyncResult *res,
GError **error);
static void g_file_real_make_symbolic_link_async (GFile *file,
const char *symlink_value,
int io_priority,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
static gboolean g_file_real_make_symbolic_link_finish (GFile *file,
GAsyncResult *result,
GError **error);
static void g_file_real_open_readwrite_async (GFile *file,
int io_priority,
GCancellable *cancellable,
@ -399,6 +410,8 @@ g_file_default_init (GFileIface *iface)
iface->move_finish = g_file_real_move_finish;
iface->make_directory_async = g_file_real_make_directory_async;
iface->make_directory_finish = g_file_real_make_directory_finish;
iface->make_symbolic_link_async = g_file_real_make_symbolic_link_async;
iface->make_symbolic_link_finish = g_file_real_make_symbolic_link_finish;
iface->open_readwrite_async = g_file_real_open_readwrite_async;
iface->open_readwrite_finish = g_file_real_open_readwrite_finish;
iface->create_readwrite_async = g_file_real_create_readwrite_async;
@ -4154,6 +4167,125 @@ g_file_make_symbolic_link (GFile *file,
return (* iface->make_symbolic_link) (file, symlink_value, cancellable, error);
}
static void
make_symbolic_link_async_thread (GTask *task,
gpointer object,
gpointer task_data,
GCancellable *cancellable)
{
const char *symlink_value = task_data;
GError *error = NULL;
if (g_file_make_symbolic_link (G_FILE (object), symlink_value, cancellable, &error))
g_task_return_boolean (task, TRUE);
else
g_task_return_error (task, g_steal_pointer (&error));
}
static void
g_file_real_make_symbolic_link_async (GFile *file,
const char *symlink_value,
int io_priority,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GTask *task;
g_return_if_fail (G_IS_FILE (file));
g_return_if_fail (symlink_value != NULL);
g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
task = g_task_new (file, cancellable, callback, user_data);
g_task_set_source_tag (task, g_file_real_make_symbolic_link_async);
g_task_set_task_data (task, g_strdup (symlink_value), g_free);
g_task_set_priority (task, io_priority);
g_task_run_in_thread (task, make_symbolic_link_async_thread);
g_object_unref (task);
}
/**
* g_file_make_symbolic_link_async:
* @file: a #GFile with the name of the symlink to create
* @symlink_value: (type filename): a string with the path for the target
* of the new symlink
* @io_priority: the [I/O priority][io-priority] of the request
* @cancellable: (nullable): optional #GCancellable object,
* %NULL to ignore
* @callback: a #GAsyncReadyCallback to call
* when the request is satisfied
* @user_data: the data to pass to callback function
*
* Asynchronously creates a symbolic link named @file which contains the
* string @symlink_value.
*
* Virtual: make_symbolic_link_async
* Since: 2.74
*/
void
g_file_make_symbolic_link_async (GFile *file,
const char *symlink_value,
int io_priority,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GFileIface *iface;
g_return_if_fail (G_IS_FILE (file));
g_return_if_fail (symlink_value != NULL);
g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
iface = G_FILE_GET_IFACE (file);
/* Default implementation should always be provided by GFileIface */
g_assert (iface->make_symbolic_link_async != NULL);
(* iface->make_symbolic_link_async) (file, symlink_value, io_priority,
cancellable, callback, user_data);
}
static gboolean
g_file_real_make_symbolic_link_finish (GFile *file,
GAsyncResult *result,
GError **error)
{
g_return_val_if_fail (g_task_is_valid (result, file), FALSE);
return g_task_propagate_boolean (G_TASK (result), error);
}
/**
* g_file_make_symbolic_link_finish:
* @file: input #GFile
* @result: a #GAsyncResult
* @error: a #GError, or %NULL
*
* Finishes an asynchronous symbolic link creation, started with
* g_file_make_symbolic_link_async().
*
* Virtual: make_symbolic_link_finish
* Returns: %TRUE on successful directory creation, %FALSE otherwise.
* Since: 2.74
*/
gboolean
g_file_make_symbolic_link_finish (GFile *file,
GAsyncResult *result,
GError **error)
{
GFileIface *iface;
g_return_val_if_fail (G_IS_FILE (file), FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
iface = G_FILE_GET_IFACE (file);
/* Default implementation should always be provided by GFileIface */
g_assert (iface->make_symbolic_link_finish != NULL);
return (* iface->make_symbolic_link_finish) (file, result, error);
}
/**
* g_file_delete:
* @file: input #GFile
@ -6814,6 +6946,252 @@ g_file_new_tmp (const char *tmpl,
return file;
}
typedef struct {
GFile *file;
GFileIOStream *iostream;
} NewTmpAsyncData;
static void
new_tmp_data_free (NewTmpAsyncData *data)
{
g_clear_object (&data->file);
g_clear_object (&data->iostream);
g_free (data);
}
static void
new_tmp_async_thread (GTask *task,
gpointer object,
gpointer task_data,
GCancellable *cancellable)
{
GFile *file;
const char *tmpl = task_data;
GFileIOStream *iostream = NULL;
GError *error = NULL;
NewTmpAsyncData *return_data;
if (g_task_return_error_if_cancelled (task))
return;
file = g_file_new_tmp (tmpl, &iostream, &error);
if (!file)
{
int error_code = G_IO_ERROR_FAILED;
if (error->domain == G_IO_ERROR)
{
g_task_return_error (task, g_steal_pointer (&error));
return;
}
if (error->domain == G_FILE_ERROR)
error_code = g_io_error_from_file_error (error->code);
g_task_return_new_error (task, G_IO_ERROR, error_code,
_("Failed to create a temporary directory for "
"template “%s”: %s"),
tmpl, error->message);
g_clear_error (&error);
return;
}
return_data = g_new0 (NewTmpAsyncData, 1);
return_data->file = g_steal_pointer (&file);
return_data->iostream = g_steal_pointer (&iostream);
g_task_return_pointer (task, g_steal_pointer (&return_data),
(GDestroyNotify) new_tmp_data_free);
}
/**
* g_file_new_tmp_async:
* @tmpl: (type filename) (nullable): Template for the file
* name, as in g_file_open_tmp(), or %NULL for a default template
* @io_priority: the [I/O priority][io-priority] of the request
* @cancellable: optional #GCancellable object, %NULL to ignore
* @callback: (nullable): a #GAsyncReadyCallback to call when the request is done
* @user_data: (nullable): data to pass to @callback
*
* Asynchronously opens a file in the preferred directory for temporary files
* (as returned by g_get_tmp_dir()) as g_file_new_tmp().
*
* @tmpl should be a string in the GLib file name encoding
* containing a sequence of six 'X' characters, and containing no
* directory components. If it is %NULL, a default template is used.
*
* Since: 2.74
*/
void
g_file_new_tmp_async (const char *tmpl,
int io_priority,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GTask *task;
g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
task = g_task_new (NULL, cancellable, callback, user_data);
g_task_set_source_tag (task, g_file_new_tmp_async);
g_task_set_task_data (task, g_strdup (tmpl), g_free);
g_task_set_priority (task, io_priority);
g_task_set_check_cancellable (task, TRUE);
g_task_run_in_thread (task, new_tmp_async_thread);
g_object_unref (task);
}
/**
* g_file_new_tmp_finish:
* @result: a #GAsyncResult
* @iostream: (out) (not optional) (not nullable) (transfer full): on return, a #GFileIOStream for the created file
* @error: a #GError, or %NULL
*
* Finishes a temporary file creation started by g_file_new_tmp_async().
*
* Returns: (transfer full): a new #GFile.
* Free the returned object with g_object_unref().
*
* Since: 2.74
*/
GFile *
g_file_new_tmp_finish (GAsyncResult *result,
GFileIOStream **iostream,
GError **error)
{
GFile *file;
NewTmpAsyncData *data;
g_return_val_if_fail (g_task_is_valid (result, NULL), NULL);
g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) ==
g_file_new_tmp_async, NULL);
g_return_val_if_fail (iostream != NULL, NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
data = g_task_propagate_pointer (G_TASK (result), error);
if (!data)
{
*iostream = NULL;
return NULL;
}
file = g_steal_pointer (&data->file);
*iostream = g_steal_pointer (&data->iostream);
new_tmp_data_free (data);
return file;
}
static void
new_tmp_dir_async_thread (GTask *task,
gpointer object,
gpointer task_data,
GCancellable *cancellable)
{
gchar *path;
const char *tmpl = task_data;
GError *error = NULL;
if (g_task_return_error_if_cancelled (task))
return;
path = g_dir_make_tmp (tmpl, &error);
if (!path)
{
int error_code = G_IO_ERROR_FAILED;
if (error->domain == G_IO_ERROR)
{
g_task_return_error (task, g_steal_pointer (&error));
return;
}
if (error->domain == G_FILE_ERROR)
error_code = g_io_error_from_file_error (error->code);
g_task_return_new_error (task, G_IO_ERROR, error_code,
_("Failed to create a temporary directory for "
"template “%s”: %s"),
tmpl, error->message);
g_clear_error (&error);
return;
}
g_task_return_pointer (task, g_file_new_for_path (path), g_object_unref);
g_free (path);
}
/**
* g_file_new_tmp_dir_async:
* @tmpl: (type filename) (nullable): Template for the file
* name, as in g_dir_make_tmp(), or %NULL for a default template
* @io_priority: the [I/O priority][io-priority] of the request
* @cancellable: optional #GCancellable object, %NULL to ignore
* @callback: (nullable): a #GAsyncReadyCallback to call when the request is done
* @user_data: (nullable): data to pass to @callback
*
* Asynchronously creates a directory in the preferred directory for
* temporary files (as returned by g_get_tmp_dir()) as g_dir_make_tmp().
*
* @tmpl should be a string in the GLib file name encoding
* containing a sequence of six 'X' characters, and containing no
* directory components. If it is %NULL, a default template is used.
*
* Since: 2.74
*/
void
g_file_new_tmp_dir_async (const char *tmpl,
int io_priority,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GTask *task;
g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
task = g_task_new (NULL, cancellable, callback, user_data);
g_task_set_source_tag (task, g_file_new_tmp_dir_async);
g_task_set_task_data (task, g_strdup (tmpl), g_free);
g_task_set_priority (task, io_priority);
g_task_set_check_cancellable (task, TRUE);
g_task_run_in_thread (task, new_tmp_dir_async_thread);
g_object_unref (task);
}
/**
* g_file_new_tmp_dir_finish:
* @result: a #GAsyncResult
* @error: a #GError, or %NULL
*
* Finishes a temporary directory creation started by
* g_file_new_tmp_dir_async().
*
* Returns: (transfer full): a new #GFile.
* Free the returned object with g_object_unref().
*
* Since: 2.74
*/
GFile *
g_file_new_tmp_dir_finish (GAsyncResult *result,
GError **error)
{
g_return_val_if_fail (g_task_is_valid (result, NULL), NULL);
g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) ==
g_file_new_tmp_dir_async, NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
return g_task_propagate_pointer (G_TASK (result), error);
}
/**
* g_file_parse_name:
* @parse_name: a file name or path to be parsed
@ -7145,6 +7523,36 @@ g_file_query_default_handler (GFile *file,
return NULL;
}
static void
query_default_handler_query_app_info_for_type_cb (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
GTask *task = G_TASK (user_data);
GAppInfo *appinfo;
GError *error = NULL;
appinfo = g_app_info_get_default_for_type_finish (result, &error);
if (appinfo != NULL)
{
g_task_return_pointer (task, g_steal_pointer (&appinfo), g_object_unref);
}
else if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
{
g_task_return_new_error (task,
G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
"%s", error->message);
}
else
{
g_task_return_error (task, g_steal_pointer (&error));
}
g_clear_error (&error);
g_object_unref (task);
}
static void
query_default_handler_query_info_cb (GObject *object,
GAsyncResult *result,
@ -7155,7 +7563,6 @@ query_default_handler_query_info_cb (GObject *object,
GError *error = NULL;
GFileInfo *info;
const char *content_type;
GAppInfo *appinfo = NULL;
info = g_file_query_info_finish (file, result, &error);
if (info == NULL)
@ -7170,27 +7577,58 @@ query_default_handler_query_info_cb (GObject *object,
content_type = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE);
if (content_type)
{
GCancellable *cancellable = g_task_get_cancellable (task);
char *path;
/* Don't use is_native(), as we want to support fuse paths if available */
path = g_file_get_path (file);
/* FIXME: The following still uses blocking calls. */
appinfo = g_app_info_get_default_for_type (content_type,
path == NULL);
g_app_info_get_default_for_type_async (content_type,
path == NULL,
cancellable,
query_default_handler_query_app_info_for_type_cb,
g_steal_pointer (&task));
g_free (path);
}
else
{
g_task_return_new_error (task,
G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
_("No application is registered as handling this file"));
}
g_object_unref (info);
g_clear_object (&task);
}
if (appinfo != NULL)
g_task_return_pointer (task, g_steal_pointer (&appinfo), g_object_unref);
static void
on_query_default_handler_for_uri_cb (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
GTask *task = user_data;
GAppInfo *app_info;
app_info = g_app_info_get_default_for_uri_scheme_finish (result, NULL);
if (app_info)
{
g_task_return_pointer (task, g_steal_pointer (&app_info), g_object_unref);
g_object_unref (task);
}
else
g_task_return_new_error (task,
G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
_("No application is registered as handling this file"));
g_object_unref (task);
{
g_file_query_info_async (g_task_get_source_object (task),
G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE ","
G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE,
0,
g_task_get_priority (task),
g_task_get_cancellable (task),
query_default_handler_query_info_cb,
task);
}
}
/**
@ -7221,21 +7659,13 @@ g_file_query_default_handler_async (GFile *file,
uri_scheme = g_file_get_uri_scheme (file);
if (uri_scheme && uri_scheme[0] != '\0')
{
GAppInfo *appinfo;
/* FIXME: The following still uses blocking calls. */
appinfo = g_app_info_get_default_for_uri_scheme (uri_scheme);
g_app_info_get_default_for_uri_scheme_async (uri_scheme,
cancellable,
on_query_default_handler_for_uri_cb,
g_steal_pointer (&task));
g_free (uri_scheme);
if (appinfo != NULL)
{
g_task_return_pointer (task, g_steal_pointer (&appinfo), g_object_unref);
g_object_unref (task);
return;
}
return;
}
else
g_free (uri_scheme);
g_file_query_info_async (file,
G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE ","
@ -7245,6 +7675,8 @@ g_file_query_default_handler_async (GFile *file,
cancellable,
query_default_handler_query_info_cb,
g_steal_pointer (&task));
g_free (uri_scheme);
}
/**

View File

@ -115,8 +115,8 @@ typedef struct _GFileIface GFileIface;
* @make_directory_finish: Finishes making a directory asynchronously.
* @make_symbolic_link: (nullable): Makes a symbolic link. %NULL if symbolic
* links are unsupported.
* @_make_symbolic_link_async: Asynchronously makes a symbolic link
* @_make_symbolic_link_finish: Finishes making a symbolic link asynchronously.
* @make_symbolic_link_async: Asynchronously makes a symbolic link
* @make_symbolic_link_finish: Finishes making a symbolic link asynchronously.
* @copy: (nullable): Copies a file. %NULL if copying is unsupported, which will
* cause `GFile` to use a fallback copy method where it reads from the
* source and writes to the destination.
@ -396,8 +396,15 @@ struct _GFileIface
const char *symlink_value,
GCancellable *cancellable,
GError **error);
void (* _make_symbolic_link_async) (void);
void (* _make_symbolic_link_finish) (void);
void (* make_symbolic_link_async) (GFile *file,
const char *symlink_value,
int io_priority,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean (* make_symbolic_link_finish) (GFile *file,
GAsyncResult *result,
GError **error);
gboolean (* copy) (GFile *source,
GFile *destination,
@ -619,6 +626,25 @@ GLIB_AVAILABLE_IN_2_32
GFile * g_file_new_tmp (const char *tmpl,
GFileIOStream **iostream,
GError **error);
GLIB_AVAILABLE_IN_2_74
void g_file_new_tmp_async (const char *tmpl,
int io_priority,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
GLIB_AVAILABLE_IN_2_74
GFile * g_file_new_tmp_finish (GAsyncResult *result,
GFileIOStream **iostream,
GError **error);
GLIB_AVAILABLE_IN_2_74
void g_file_new_tmp_dir_async (const char *tmpl,
int io_priority,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
GLIB_AVAILABLE_IN_2_74
GFile * g_file_new_tmp_dir_finish (GAsyncResult *result,
GError **error);
GLIB_AVAILABLE_IN_ALL
GFile * g_file_parse_name (const char *parse_name);
GLIB_AVAILABLE_IN_2_56
@ -976,6 +1002,17 @@ gboolean g_file_make_symbolic_link (GFile
const char *symlink_value,
GCancellable *cancellable,
GError **error);
GLIB_AVAILABLE_IN_2_74
void g_file_make_symbolic_link_async (GFile *file,
const char *symlink_value,
int io_priority,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
GLIB_AVAILABLE_IN_2_74
gboolean g_file_make_symbolic_link_finish (GFile *file,
GAsyncResult *result,
GError **error);
GLIB_AVAILABLE_IN_ALL
GFileAttributeInfoList *g_file_query_settable_attributes (GFile *file,
GCancellable *cancellable,

View File

@ -509,6 +509,7 @@ typedef enum {
* value, which has this more logical name. Since 2.44.
* @G_IO_ERROR_NOT_CONNECTED: Transport endpoint is not connected. Since 2.44
* @G_IO_ERROR_MESSAGE_TOO_LARGE: Message too large. Since 2.48.
* @G_IO_ERROR_NO_SUCH_DEVICE: No such device found. Since 2.74
*
* Error codes returned by GIO functions.
*
@ -577,7 +578,8 @@ typedef enum {
G_IO_ERROR_BROKEN_PIPE,
G_IO_ERROR_CONNECTION_CLOSED = G_IO_ERROR_BROKEN_PIPE,
G_IO_ERROR_NOT_CONNECTED,
G_IO_ERROR_MESSAGE_TOO_LARGE
G_IO_ERROR_MESSAGE_TOO_LARGE,
G_IO_ERROR_NO_SUCH_DEVICE,
} GIOErrorEnum;

View File

@ -1,6 +1,7 @@
/* GIO - GLib Input, Output and Streaming Library
*
* Copyright (C) 2006-2007 Red Hat, Inc.
* Copyright (C) 2022 Canonical Ltd.
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*
@ -18,6 +19,7 @@
* Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
* Author: Alexander Larsson <alexl@redhat.com>
* Author: Marco Trevisan <marco.trevisan@canonical.com>
*/
#include "config.h"
@ -71,83 +73,38 @@ G_DEFINE_QUARK (g-io-error-quark, g_io_error)
GIOErrorEnum
g_io_error_from_errno (gint err_no)
{
GFileError file_error;
GIOErrorEnum io_error;
file_error = g_file_error_from_errno (err_no);
io_error = g_io_error_from_file_error (file_error);
if (io_error != G_IO_ERROR_FAILED)
return io_error;
switch (err_no)
{
#ifdef EEXIST
case EEXIST:
return G_IO_ERROR_EXISTS;
break;
#endif
#ifdef EISDIR
case EISDIR:
return G_IO_ERROR_IS_DIRECTORY;
break;
#endif
#ifdef EACCES
case EACCES:
return G_IO_ERROR_PERMISSION_DENIED;
break;
#endif
#ifdef ENAMETOOLONG
case ENAMETOOLONG:
return G_IO_ERROR_FILENAME_TOO_LONG;
break;
#endif
#ifdef ENOENT
case ENOENT:
return G_IO_ERROR_NOT_FOUND;
break;
#endif
#ifdef ENOTDIR
case ENOTDIR:
return G_IO_ERROR_NOT_DIRECTORY;
break;
#endif
#ifdef ENXIO
case ENXIO:
return G_IO_ERROR_NOT_REGULAR_FILE;
break;
#endif
#ifdef EROFS
case EROFS:
return G_IO_ERROR_READ_ONLY;
break;
#endif
#ifdef ELOOP
case ELOOP:
#ifdef EMLINK
case EMLINK:
return G_IO_ERROR_TOO_MANY_LINKS;
break;
#endif
#ifdef ENOSPC
case ENOSPC:
return G_IO_ERROR_NO_SPACE;
#ifdef ENOMSG
case ENOMSG:
return G_IO_ERROR_INVALID_DATA;
break;
#endif
#ifdef ENOMEM
case ENOMEM:
return G_IO_ERROR_NO_SPACE;
#ifdef ENODATA
case ENODATA:
return G_IO_ERROR_INVALID_DATA;
break;
#endif
#ifdef EINVAL
case EINVAL:
return G_IO_ERROR_INVALID_ARGUMENT;
break;
#endif
#ifdef EPERM
case EPERM:
return G_IO_ERROR_PERMISSION_DENIED;
#ifdef EBADMSG
case EBADMSG:
return G_IO_ERROR_INVALID_DATA;
break;
#endif
@ -226,12 +183,6 @@ g_io_error_from_errno (gint err_no)
break;
#endif
#ifdef EMFILE
case EMFILE:
return G_IO_ERROR_TOO_MANY_OPEN_FILES;
break;
#endif
#ifdef EADDRINUSE
case EADDRINUSE:
return G_IO_ERROR_ADDRESS_IN_USE;
@ -250,15 +201,15 @@ g_io_error_from_errno (gint err_no)
break;
#endif
#ifdef ECONNREFUSED
case ECONNREFUSED:
return G_IO_ERROR_CONNECTION_REFUSED;
#ifdef ENETDOWN
case ENETDOWN:
return G_IO_ERROR_NETWORK_UNREACHABLE;
break;
#endif
#ifdef EPIPE
case EPIPE:
return G_IO_ERROR_BROKEN_PIPE;
#ifdef ECONNREFUSED
case ECONNREFUSED:
return G_IO_ERROR_CONNECTION_REFUSED;
break;
#endif
@ -292,6 +243,70 @@ g_io_error_from_errno (gint err_no)
}
}
/**
* g_io_error_from_file_error:
* @file_error: a #GFileError.
*
* Converts #GFileError error codes into GIO error codes.
*
* Returns: #GIOErrorEnum value for the given #GFileError error value.
*
* Since: 2.74
**/
GIOErrorEnum
g_io_error_from_file_error (GFileError file_error)
{
switch (file_error)
{
case G_FILE_ERROR_EXIST:
return G_IO_ERROR_EXISTS;
case G_FILE_ERROR_ISDIR:
return G_IO_ERROR_IS_DIRECTORY;
case G_FILE_ERROR_ACCES:
return G_IO_ERROR_PERMISSION_DENIED;
case G_FILE_ERROR_NAMETOOLONG:
return G_IO_ERROR_FILENAME_TOO_LONG;
case G_FILE_ERROR_NOENT:
return G_IO_ERROR_NOT_FOUND;
case G_FILE_ERROR_NOTDIR:
return G_IO_ERROR_NOT_DIRECTORY;
case G_FILE_ERROR_NXIO:
return G_IO_ERROR_NOT_REGULAR_FILE;
case G_FILE_ERROR_NODEV:
return G_IO_ERROR_NO_SUCH_DEVICE;
case G_FILE_ERROR_ROFS:
return G_IO_ERROR_READ_ONLY;
case G_FILE_ERROR_TXTBSY:
return G_IO_ERROR_BUSY;
case G_FILE_ERROR_LOOP:
return G_IO_ERROR_TOO_MANY_LINKS;
case G_FILE_ERROR_NOSPC:
case G_FILE_ERROR_NOMEM:
return G_IO_ERROR_NO_SPACE;
case G_FILE_ERROR_MFILE:
case G_FILE_ERROR_NFILE:
return G_IO_ERROR_TOO_MANY_OPEN_FILES;
case G_FILE_ERROR_INVAL:
return G_IO_ERROR_INVALID_ARGUMENT;
case G_FILE_ERROR_PIPE:
return G_IO_ERROR_BROKEN_PIPE;
case G_FILE_ERROR_AGAIN:
return G_IO_ERROR_WOULD_BLOCK;
case G_FILE_ERROR_PERM:
return G_IO_ERROR_PERMISSION_DENIED;
case G_FILE_ERROR_NOSYS:
return G_IO_ERROR_NOT_SUPPORTED;
case G_FILE_ERROR_BADF:
case G_FILE_ERROR_FAILED:
case G_FILE_ERROR_FAULT:
case G_FILE_ERROR_INTR:
case G_FILE_ERROR_IO:
return G_IO_ERROR_FAILED;
default:
g_return_val_if_reached (G_IO_ERROR_FAILED);
}
}
#ifdef G_OS_WIN32
/**

View File

@ -29,6 +29,7 @@
#include <glib.h>
#include <gio/gioenums.h>
#include <glib/gfileutils.h>
G_BEGIN_DECLS
@ -44,6 +45,8 @@ GLIB_AVAILABLE_IN_ALL
GQuark g_io_error_quark (void);
GLIB_AVAILABLE_IN_ALL
GIOErrorEnum g_io_error_from_errno (gint err_no);
GLIB_AVAILABLE_IN_2_74
GIOErrorEnum g_io_error_from_file_error (GFileError file_error);
#ifdef G_OS_WIN32
GLIB_AVAILABLE_IN_ALL

View File

@ -30,21 +30,34 @@
#include <unistd.h>
static GAppInfo *
create_app_info (const char *name)
create_command_line_app_info (const char *name,
const char *command_line,
const char *default_for_type)
{
GError *error;
GAppInfo *info;
GError *error = NULL;
error = NULL;
info = g_app_info_create_from_commandline ("true blah",
info = g_app_info_create_from_commandline (command_line,
name,
G_APP_INFO_CREATE_NONE,
&error);
g_assert_no_error (error);
/* this is necessary to ensure that the info is saved */
g_app_info_set_as_default_for_type (info, "application/x-blah", &error);
g_app_info_set_as_default_for_type (info, default_for_type, &error);
g_assert_no_error (error);
return g_steal_pointer (&info);
}
static GAppInfo *
create_app_info (const char *name)
{
GError *error = NULL;
GAppInfo *info;
info = create_command_line_app_info (name, "true blah", "application/x-blah");
/* this is necessary to ensure that the info is saved */
g_app_info_remove_supports_type (info, "application/x-blah", &error);
g_assert_no_error (error);
g_app_info_reset_type_associations ("application/x-blah");
@ -119,6 +132,23 @@ test_default (void)
g_assert_cmpstr (g_app_info_get_id (info), ==, g_app_info_get_id (info2));
g_object_unref (info);
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*uri_scheme*failed*");
g_assert_null (g_app_info_get_default_for_uri_scheme (NULL));
g_test_assert_expected_messages ();
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*uri_scheme*failed*");
g_assert_null (g_app_info_get_default_for_uri_scheme (""));
g_test_assert_expected_messages ();
g_app_info_set_as_default_for_type (info3, "x-scheme-handler/glib", &error);
g_assert_no_error (error);
info = g_app_info_get_default_for_uri_scheme ("glib");
g_assert_nonnull (info);
g_assert_true (g_app_info_equal (info, info3));
g_object_unref (info);
/* now try adding something, but not setting as default */
g_app_info_add_supports_type (info3, "application/x-test", &error);
g_assert_no_error (error);
@ -141,6 +171,170 @@ test_default (void)
/* now clean it all up */
g_app_info_reset_type_associations ("application/x-test");
g_app_info_reset_type_associations ("x-scheme-handler/glib");
list = g_app_info_get_all_for_type ("application/x-test");
g_assert_null (list);
list = g_app_info_get_all_for_type ("x-scheme-handler/glib");
g_assert_null (list);
g_app_info_delete (info1);
g_app_info_delete (info2);
g_app_info_delete (info3);
g_object_unref (info1);
g_object_unref (info2);
g_object_unref (info3);
}
typedef struct
{
GAppInfo *expected_info;
GMainLoop *loop;
} DefaultForTypeData;
static void
ensure_default_type_result (GAppInfo *info,
DefaultForTypeData *data,
GError *error)
{
if (data->expected_info)
{
g_assert_nonnull (info);
g_assert_no_error (error);
g_assert_true (g_app_info_equal (info, data->expected_info));
}
else
{
g_assert_null (info);
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND);
}
g_main_loop_quit (data->loop);
g_clear_object (&info);
g_clear_error (&error);
}
static void
on_default_for_type_cb (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
GAppInfo *info;
GError *error = NULL;
DefaultForTypeData *data = user_data;
g_assert_null (object);
info = g_app_info_get_default_for_type_finish (result, &error);
ensure_default_type_result (info, data, error);
}
static void
on_default_for_uri_cb (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
GAppInfo *info;
GError *error = NULL;
DefaultForTypeData *data = user_data;
g_assert_null (object);
info = g_app_info_get_default_for_uri_scheme_finish (result, &error);
ensure_default_type_result (info, data, error);
}
static void
test_default_async (void)
{
DefaultForTypeData data;
GAppInfo *info1, *info2, *info3;
GList *list;
GError *error = NULL;
data.loop = g_main_loop_new (NULL, TRUE);
info1 = create_app_info ("Blah1");
info2 = create_app_info ("Blah2");
info3 = create_app_info ("Blah3");
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*content_type*failed*");
g_app_info_get_default_for_type_async (NULL, FALSE, NULL, NULL, NULL);
g_test_assert_expected_messages ();
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*content_type*failed*");
g_app_info_get_default_for_type_async ("", FALSE, NULL, NULL, NULL);
g_test_assert_expected_messages ();
g_app_info_set_as_default_for_type (info1, "application/x-test", &error);
g_assert_no_error (error);
g_app_info_set_as_default_for_type (info2, "application/x-test", &error);
g_assert_no_error (error);
data.expected_info = info2;
g_app_info_get_default_for_type_async ("application/x-test", FALSE,
NULL, on_default_for_type_cb, &data);
g_main_loop_run (data.loop);
/* now try adding something, but not setting as default */
g_app_info_add_supports_type (info3, "application/x-test", &error);
g_assert_no_error (error);
/* check that info2 is still default */
data.expected_info = info2;
g_app_info_get_default_for_type_async ("application/x-test", FALSE,
NULL, on_default_for_type_cb, &data);
g_main_loop_run (data.loop);
/* now remove info1 again */
g_app_info_remove_supports_type (info1, "application/x-test", &error);
g_assert_no_error (error);
/* and make sure info2 is still default */
data.expected_info = info2;
g_app_info_get_default_for_type_async ("application/x-test", FALSE,
NULL, on_default_for_type_cb, &data);
g_main_loop_run (data.loop);
g_app_info_set_as_default_for_type (info3, "x-scheme-handler/glib-async", &error);
g_assert_no_error (error);
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*uri_scheme*failed*");
g_assert_null (g_app_info_get_default_for_uri_scheme (NULL));
g_test_assert_expected_messages ();
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*uri_scheme*failed*");
g_assert_null (g_app_info_get_default_for_uri_scheme (""));
g_test_assert_expected_messages ();
data.expected_info = info3;
g_app_info_get_default_for_uri_scheme_async ("glib-async", NULL,
on_default_for_uri_cb, &data);
g_main_loop_run (data.loop);
/* now clean it all up */
g_app_info_reset_type_associations ("application/x-test");
data.expected_info = NULL;
g_app_info_get_default_for_type_async ("application/x-test", FALSE,
NULL, on_default_for_type_cb, &data);
g_main_loop_run (data.loop);
g_app_info_reset_type_associations ("x-scheme-handler/glib-async");
data.expected_info = NULL;
g_app_info_get_default_for_uri_scheme_async ("glib-async", NULL,
on_default_for_uri_cb, &data);
g_main_loop_run (data.loop);
list = g_app_info_get_all_for_type ("application/x-test");
g_assert_null (list);
@ -152,6 +346,8 @@ test_default (void)
g_object_unref (info1);
g_object_unref (info2);
g_object_unref (info3);
g_main_loop_unref (data.loop);
}
static void
@ -799,6 +995,164 @@ test_launch_as_manager (void)
g_assert_finalize_object (context);
}
static GAppInfo *
create_app_info_toucher (const char *name,
const char *touched_file_name,
const char *handled_type,
char **out_file_path)
{
GError *error = NULL;
GAppInfo *info;
gchar *command_line;
gchar *file_path;
gchar *tmpdir;
g_assert_nonnull (out_file_path);
tmpdir = g_dir_make_tmp ("desktop-app-info-launch-XXXXXX", &error);
g_assert_no_error (error);
file_path = g_build_filename (tmpdir, touched_file_name, NULL);
command_line = g_strdup_printf ("touch %s", file_path);
info = create_command_line_app_info (name, command_line, handled_type);
*out_file_path = g_steal_pointer (&file_path);
g_free (tmpdir);
g_free (command_line);
return info;
}
static void
test_default_uri_handler (void)
{
GError *error = NULL;
gchar *file_path = NULL;
GAppInfo *info;
info = create_app_info_toucher ("Touch Handled", "handled",
"x-scheme-handler/glib-touch",
&file_path);
g_assert_true (G_IS_APP_INFO (info));
g_assert_nonnull (file_path);
g_assert_true (g_app_info_launch_default_for_uri ("glib-touch://touch-me",
NULL, &error));
g_assert_no_error (error);
while (!g_file_test (file_path, G_FILE_TEST_IS_REGULAR));
g_assert_true (g_file_test (file_path, G_FILE_TEST_IS_REGULAR));
g_assert_false (g_app_info_launch_default_for_uri ("glib-INVALID-touch://touch-me",
NULL, &error));
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
g_clear_error (&error);
g_object_unref (info);
g_free (file_path);
}
static void
on_launch_default_for_uri_success_cb (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
GError *error = NULL;
gboolean *called = user_data;
g_assert_true (g_app_info_launch_default_for_uri_finish (result, &error));
g_assert_no_error (error);
*called = TRUE;
}
static void
on_launch_default_for_uri_not_found_cb (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
GError *error = NULL;
GMainLoop *loop = user_data;
g_assert_false (g_app_info_launch_default_for_uri_finish (result, &error));
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
g_clear_error (&error);
g_main_loop_quit (loop);
}
static void
on_launch_default_for_uri_cancelled_cb (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
GError *error = NULL;
GMainLoop *loop = user_data;
g_assert_false (g_app_info_launch_default_for_uri_finish (result, &error));
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
g_clear_error (&error);
g_main_loop_quit (loop);
}
static void
test_default_uri_handler_async (void)
{
GCancellable *cancellable;
gchar *file_path = NULL;
GAppInfo *info;
GMainLoop *loop;
gboolean called = FALSE;
loop = g_main_loop_new (NULL, FALSE);
info = create_app_info_toucher ("Touch Handled", "handled-async",
"x-scheme-handler/glib-async-touch",
&file_path);
g_assert_true (G_IS_APP_INFO (info));
g_assert_nonnull (file_path);
g_app_info_launch_default_for_uri_async ("glib-async-touch://touch-me", NULL,
NULL,
on_launch_default_for_uri_success_cb,
&called);
while (!g_file_test (file_path, G_FILE_TEST_IS_REGULAR))
g_main_context_iteration (NULL, FALSE);
g_assert_true (called);
g_assert_true (g_file_test (file_path, G_FILE_TEST_IS_REGULAR));
g_unlink (file_path);
g_assert_false (g_file_test (file_path, G_FILE_TEST_IS_REGULAR));
g_app_info_launch_default_for_uri_async ("glib-async-INVALID-touch://touch-me",
NULL, NULL,
on_launch_default_for_uri_not_found_cb,
loop);
g_main_loop_run (loop);
cancellable = g_cancellable_new ();
g_app_info_launch_default_for_uri_async ("glib-async-touch://touch-me", NULL,
cancellable,
on_launch_default_for_uri_cancelled_cb,
loop);
g_cancellable_cancel (cancellable);
g_main_loop_run (loop);
/* Once started our touch app may take some time before having written the
* file, so let's wait a bit here before ensuring that the file has been
* created as expected.
*/
g_usleep (G_USEC_PER_SEC / 10);
g_assert_false (g_file_test (file_path, G_FILE_TEST_IS_REGULAR));
g_object_unref (info);
g_main_loop_unref (loop);
g_free (file_path);
}
/* Test if Desktop-File Id is correctly formed */
static void
test_id (void)
@ -824,6 +1178,7 @@ main (int argc,
g_test_add_func ("/desktop-app-info/delete", test_delete);
g_test_add_func ("/desktop-app-info/default", test_default);
g_test_add_func ("/desktop-app-info/default-async", test_default_async);
g_test_add_func ("/desktop-app-info/fallback", test_fallback);
g_test_add_func ("/desktop-app-info/lastused", test_last_used);
g_test_add_func ("/desktop-app-info/extra-getters", test_extra_getters);
@ -832,6 +1187,8 @@ main (int argc,
g_test_add_func ("/desktop-app-info/implements", test_implements);
g_test_add_func ("/desktop-app-info/show-in", test_show_in);
g_test_add_func ("/desktop-app-info/launch-as-manager", test_launch_as_manager);
g_test_add_func ("/desktop-app-info/launch-default-uri-handler", test_default_uri_handler);
g_test_add_func ("/desktop-app-info/launch-default-uri-handler-async", test_default_uri_handler_async);
g_test_add_func ("/desktop-app-info/id", test_id);
return g_test_run ();

856
gio/tests/error.c Normal file
View File

@ -0,0 +1,856 @@
/* Unit tests for gioerror
* GIO - GLib Input, Output and Streaming Library
*
* Copyright (C) 2022 Marco Trevisan
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*
* 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.1 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, see <http://www.gnu.org/licenses/>.
*
* Author: Marco Trevisan <marco.trevisan@canonical.com>
*/
#include "config.h"
#include <errno.h>
#include <gio/gio.h>
#ifdef G_OS_WIN32
#include <winsock2.h>
#endif
/* We are testing some deprecated APIs here */
#ifndef GLIB_DISABLE_DEPRECATION_WARNINGS
#define GLIB_DISABLE_DEPRECATION_WARNINGS
#endif
static void
test_error_from_errno (void)
{
g_assert_cmpint (g_io_error_from_errno (-1), ==, G_IO_ERROR_FAILED);
#ifdef EEXIST
g_assert_cmpint (g_io_error_from_errno (EEXIST), ==,
G_IO_ERROR_EXISTS);
#endif
#ifdef EISDIR
g_assert_cmpint (g_io_error_from_errno (EISDIR), ==,
G_IO_ERROR_IS_DIRECTORY);
#endif
#ifdef EACCES
g_assert_cmpint (g_io_error_from_errno (EACCES), ==,
G_IO_ERROR_PERMISSION_DENIED);
#endif
#ifdef ENAMETOOLONG
g_assert_cmpint (g_io_error_from_errno (ENAMETOOLONG), ==,
G_IO_ERROR_FILENAME_TOO_LONG);
#endif
#ifdef ENOENT
g_assert_cmpint (g_io_error_from_errno (ENOENT), ==,
G_IO_ERROR_NOT_FOUND);
#endif
#ifdef ENOTDIR
g_assert_cmpint (g_io_error_from_errno (ENOTDIR), ==,
G_IO_ERROR_NOT_DIRECTORY);
#endif
#ifdef ENXIO
g_assert_cmpint (g_io_error_from_errno (ENXIO), ==,
G_IO_ERROR_NOT_REGULAR_FILE);
#endif
#ifdef EROFS
g_assert_cmpint (g_io_error_from_errno (EROFS), ==,
G_IO_ERROR_READ_ONLY);
#endif
#ifdef ELOOP
g_assert_cmpint (g_io_error_from_errno (ELOOP), ==,
G_IO_ERROR_TOO_MANY_LINKS);
#endif
#ifdef EMLINK
g_assert_cmpint (g_io_error_from_errno (EMLINK), ==,
G_IO_ERROR_TOO_MANY_LINKS);
#endif
#ifdef ENOSPC
g_assert_cmpint (g_io_error_from_errno (ENOSPC), ==,
G_IO_ERROR_NO_SPACE);
#endif
#ifdef ENOMEM
g_assert_cmpint (g_io_error_from_errno (ENOMEM), ==,
G_IO_ERROR_NO_SPACE);
#endif
#ifdef EINVAL
g_assert_cmpint (g_io_error_from_errno (EINVAL), ==,
G_IO_ERROR_INVALID_ARGUMENT);
#endif
#ifdef EPERM
g_assert_cmpint (g_io_error_from_errno (EPERM), ==,
G_IO_ERROR_PERMISSION_DENIED);
#endif
#ifdef ECANCELED
g_assert_cmpint (g_io_error_from_errno (ECANCELED), ==,
G_IO_ERROR_CANCELLED);
#endif
#ifdef ENOTEMPTY
g_assert_cmpint (g_io_error_from_errno (ENOTEMPTY), ==,
G_IO_ERROR_NOT_EMPTY);
#endif
#ifdef ENOTSUP
g_assert_cmpint (g_io_error_from_errno (ENOTSUP), ==,
G_IO_ERROR_NOT_SUPPORTED);
#endif
#ifdef EOPNOTSUPP
g_assert_cmpint (g_io_error_from_errno (EOPNOTSUPP), ==,
G_IO_ERROR_NOT_SUPPORTED);
#endif
#ifdef EPROTONOSUPPORT
g_assert_cmpint (g_io_error_from_errno (EPROTONOSUPPORT), ==,
G_IO_ERROR_NOT_SUPPORTED);
#endif
#ifdef ESOCKTNOSUPPORT
g_assert_cmpint (g_io_error_from_errno (ESOCKTNOSUPPORT), ==,
G_IO_ERROR_NOT_SUPPORTED);
#endif
#ifdef EPFNOSUPPORT
g_assert_cmpint (g_io_error_from_errno (EPFNOSUPPORT), ==,
G_IO_ERROR_NOT_SUPPORTED);
#endif
#ifdef EAFNOSUPPORT
g_assert_cmpint (g_io_error_from_errno (EAFNOSUPPORT), ==,
G_IO_ERROR_NOT_SUPPORTED);
#endif
#ifdef ETIMEDOUT
g_assert_cmpint (g_io_error_from_errno (ETIMEDOUT), ==,
G_IO_ERROR_TIMED_OUT);
#endif
#ifdef EBUSY
g_assert_cmpint (g_io_error_from_errno (EBUSY), ==,
G_IO_ERROR_BUSY);
#endif
#ifdef EWOULDBLOCK
g_assert_cmpint (g_io_error_from_errno (EWOULDBLOCK), ==,
G_IO_ERROR_WOULD_BLOCK);
#endif
#ifdef EAGAIN
g_assert_cmpint (g_io_error_from_errno (EAGAIN), ==,
G_IO_ERROR_WOULD_BLOCK);
#endif
#ifdef EMFILE
g_assert_cmpint (g_io_error_from_errno (EMFILE), ==,
G_IO_ERROR_TOO_MANY_OPEN_FILES);
#endif
#ifdef EADDRINUSE
g_assert_cmpint (g_io_error_from_errno (EADDRINUSE), ==,
G_IO_ERROR_ADDRESS_IN_USE);
#endif
#ifdef EHOSTUNREACH
g_assert_cmpint (g_io_error_from_errno (EHOSTUNREACH), ==,
G_IO_ERROR_HOST_UNREACHABLE);
#endif
#ifdef ENETUNREACH
g_assert_cmpint (g_io_error_from_errno (ENETUNREACH), ==,
G_IO_ERROR_NETWORK_UNREACHABLE);
#endif
#ifdef ECONNREFUSED
g_assert_cmpint (g_io_error_from_errno (ECONNREFUSED), ==,
G_IO_ERROR_CONNECTION_REFUSED);
#endif
#ifdef EPIPE
g_assert_cmpint (g_io_error_from_errno (EPIPE), ==,
G_IO_ERROR_BROKEN_PIPE);
#endif
#ifdef ECONNRESET
g_assert_cmpint (g_io_error_from_errno (ECONNRESET), ==,
G_IO_ERROR_CONNECTION_CLOSED);
#endif
#ifdef ENOTCONN
g_assert_cmpint (g_io_error_from_errno (ENOTCONN), ==,
G_IO_ERROR_NOT_CONNECTED);
#endif
#ifdef EMSGSIZE
g_assert_cmpint (g_io_error_from_errno (EMSGSIZE), ==,
G_IO_ERROR_MESSAGE_TOO_LARGE);
#endif
#ifdef ENOTSOCK
g_assert_cmpint (g_io_error_from_errno (ENOTSOCK), ==,
G_IO_ERROR_INVALID_ARGUMENT);
#endif
#ifdef ESRCH
g_assert_cmpint (g_io_error_from_errno (ESRCH), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef EINTR
g_assert_cmpint (g_io_error_from_errno (EINTR), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef EIO
g_assert_cmpint (g_io_error_from_errno (EIO), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef E2BIG
g_assert_cmpint (g_io_error_from_errno (E2BIG), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef ENOEXEC
g_assert_cmpint (g_io_error_from_errno (ENOEXEC), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef EBADF
g_assert_cmpint (g_io_error_from_errno (EBADF), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef ECHILD
g_assert_cmpint (g_io_error_from_errno (ECHILD), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef EFAULT
g_assert_cmpint (g_io_error_from_errno (EFAULT), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef ENOTBLK
g_assert_cmpint (g_io_error_from_errno (ENOTBLK), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef EXDEV
g_assert_cmpint (g_io_error_from_errno (EXDEV), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef ENODEV
g_assert_cmpint (g_io_error_from_errno (ENODEV), ==,
G_IO_ERROR_NO_SUCH_DEVICE);
#endif
#ifdef ENFILE
g_assert_cmpint (g_io_error_from_errno (ENFILE), ==,
G_IO_ERROR_TOO_MANY_OPEN_FILES);
#endif
#ifdef ENOTTY
g_assert_cmpint (g_io_error_from_errno (ENOTTY), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef ETXTBSY
g_assert_cmpint (g_io_error_from_errno (ETXTBSY), ==,
G_IO_ERROR_BUSY);
#endif
#ifdef EFBIG
g_assert_cmpint (g_io_error_from_errno (EFBIG), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef ESPIPE
g_assert_cmpint (g_io_error_from_errno (ESPIPE), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef EDOM
g_assert_cmpint (g_io_error_from_errno (EDOM), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef ERANGE
g_assert_cmpint (g_io_error_from_errno (ERANGE), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef EDEADLK
g_assert_cmpuint (g_io_error_from_errno (EDEADLK), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef ENOLCK
g_assert_cmpuint (g_io_error_from_errno (ENOLCK), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef ENOSYS
g_assert_cmpuint (g_io_error_from_errno (ENOSYS), ==,
G_IO_ERROR_NOT_SUPPORTED);
#endif
#ifdef ENOMSG
g_assert_cmpuint (g_io_error_from_errno (ENOMSG), ==,
G_IO_ERROR_INVALID_DATA);
#endif
#ifdef EIDRM
g_assert_cmpuint (g_io_error_from_errno (EIDRM), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef ECHRNG
g_assert_cmpuint (g_io_error_from_errno (ECHRNG), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef EL2NSYNC
g_assert_cmpuint (g_io_error_from_errno (EL2NSYNC), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef EL3HLT
g_assert_cmpuint (g_io_error_from_errno (EL3HLT), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef EL3RST
g_assert_cmpuint (g_io_error_from_errno (EL3RST), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef ELNRNG
g_assert_cmpuint (g_io_error_from_errno (ELNRNG), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef EUNATCH
g_assert_cmpuint (g_io_error_from_errno (EUNATCH), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef ENOCSI
g_assert_cmpuint (g_io_error_from_errno (ENOCSI), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef EL2HLT
g_assert_cmpuint (g_io_error_from_errno (EL2HLT), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef EBADE
g_assert_cmpuint (g_io_error_from_errno (EBADE), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef EBADR
g_assert_cmpuint (g_io_error_from_errno (EBADR), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef EXFULL
g_assert_cmpuint (g_io_error_from_errno (EXFULL), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef ENOANO
g_assert_cmpuint (g_io_error_from_errno (ENOANO), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef EBADRQC
g_assert_cmpuint (g_io_error_from_errno (EBADRQC), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef EBADSLT
g_assert_cmpuint (g_io_error_from_errno (EBADSLT), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef EDEADLOCK
g_assert_cmpuint (g_io_error_from_errno (EDEADLOCK), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef EBFONT
g_assert_cmpuint (g_io_error_from_errno (EBFONT), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef ENOSTR
g_assert_cmpuint (g_io_error_from_errno (ENOSTR), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef ENODATA
g_assert_cmpuint (g_io_error_from_errno (ENODATA), ==,
G_IO_ERROR_INVALID_DATA);
#endif
#ifdef ETIME
g_assert_cmpuint (g_io_error_from_errno (ETIME), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef ENOSR
g_assert_cmpuint (g_io_error_from_errno (ENOSR), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef ENONET
g_assert_cmpuint (g_io_error_from_errno (ENONET), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef ENOPKG
g_assert_cmpuint (g_io_error_from_errno (ENOPKG), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef EREMOTE
g_assert_cmpuint (g_io_error_from_errno (EREMOTE), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef ENOLINK
g_assert_cmpuint (g_io_error_from_errno (ENOLINK), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef EADV
g_assert_cmpuint (g_io_error_from_errno (EADV), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef ESRMNT
g_assert_cmpuint (g_io_error_from_errno (ESRMNT), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef ECOMM
g_assert_cmpuint (g_io_error_from_errno (ECOMM), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef EPROTO
g_assert_cmpuint (g_io_error_from_errno (EPROTO), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef EMULTIHOP
g_assert_cmpuint (g_io_error_from_errno (EMULTIHOP), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef EDOTDOT
g_assert_cmpuint (g_io_error_from_errno (EDOTDOT), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef EBADMSG
g_assert_cmpuint (g_io_error_from_errno (EBADMSG), ==,
G_IO_ERROR_INVALID_DATA);
#endif
#ifdef EOVERFLOW
g_assert_cmpuint (g_io_error_from_errno (EOVERFLOW), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef ENOTUNIQ
g_assert_cmpuint (g_io_error_from_errno (ENOTUNIQ), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef EBADFD
g_assert_cmpuint (g_io_error_from_errno (EBADFD), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef EREMCHG
g_assert_cmpuint (g_io_error_from_errno (EREMCHG), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef ELIBACC
g_assert_cmpuint (g_io_error_from_errno (ELIBACC), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef ELIBBAD
g_assert_cmpuint (g_io_error_from_errno (ELIBBAD), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef ELIBSCN
g_assert_cmpuint (g_io_error_from_errno (ELIBSCN), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef ELIBMAX
g_assert_cmpuint (g_io_error_from_errno (ELIBMAX), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef ELIBEXEC
g_assert_cmpuint (g_io_error_from_errno (ELIBEXEC), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef EILSEQ
g_assert_cmpuint (g_io_error_from_errno (EILSEQ), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef ERESTART
g_assert_cmpuint (g_io_error_from_errno (ERESTART), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef ESTRPIPE
g_assert_cmpuint (g_io_error_from_errno (ESTRPIPE), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef EUSERS
g_assert_cmpuint (g_io_error_from_errno (EUSERS), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef EDESTADDRREQ
g_assert_cmpuint (g_io_error_from_errno (EDESTADDRREQ), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef EPROTOTYPE
g_assert_cmpuint (g_io_error_from_errno (EPROTOTYPE), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef ENOPROTOOPT
g_assert_cmpuint (g_io_error_from_errno (ENOPROTOOPT), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef EADDRNOTAVAIL
g_assert_cmpuint (g_io_error_from_errno (EADDRNOTAVAIL), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef ENETDOWN
g_assert_cmpuint (g_io_error_from_errno (ENETDOWN), ==,
G_IO_ERROR_NETWORK_UNREACHABLE);
#endif
#ifdef ECONNABORTED
g_assert_cmpuint (g_io_error_from_errno (ECONNABORTED), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef ENOBUFS
g_assert_cmpuint (g_io_error_from_errno (ENOBUFS), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef EISCONN
g_assert_cmpuint (g_io_error_from_errno (EISCONN), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef ESHUTDOWN
g_assert_cmpuint (g_io_error_from_errno (ESHUTDOWN), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef ETOOMANYREFS
g_assert_cmpuint (g_io_error_from_errno (ETOOMANYREFS), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef EHOSTDOWN
g_assert_cmpuint (g_io_error_from_errno (EHOSTDOWN), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef EALREADY
g_assert_cmpuint (g_io_error_from_errno (EALREADY), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef EINPROGRESS
g_assert_cmpuint (g_io_error_from_errno (EINPROGRESS), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef ESTALE
g_assert_cmpuint (g_io_error_from_errno (ESTALE), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef EUCLEAN
g_assert_cmpuint (g_io_error_from_errno (EUCLEAN), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef ENOTNAM
g_assert_cmpuint (g_io_error_from_errno (ENOTNAM), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef ENAVAIL
g_assert_cmpuint (g_io_error_from_errno (ENAVAIL), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef EISNAM
g_assert_cmpuint (g_io_error_from_errno (EISNAM), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef EREMOTEIO
g_assert_cmpuint (g_io_error_from_errno (EREMOTEIO), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef EDQUOT
g_assert_cmpuint (g_io_error_from_errno (EDQUOT), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef ENOMEDIUM
g_assert_cmpuint (g_io_error_from_errno (ENOMEDIUM), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef EMEDIUMTYPE
g_assert_cmpuint (g_io_error_from_errno (EMEDIUMTYPE), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef ENOKEY
g_assert_cmpuint (g_io_error_from_errno (ENOKEY), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef EKEYEXPIRED
g_assert_cmpuint (g_io_error_from_errno (EKEYEXPIRED), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef EKEYREVOKED
g_assert_cmpuint (g_io_error_from_errno (EKEYREVOKED), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef EKEYREJECTED
g_assert_cmpuint (g_io_error_from_errno (EKEYREJECTED), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef EOWNERDEAD
g_assert_cmpuint (g_io_error_from_errno (EOWNERDEAD), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef ENOTRECOVERABLE
g_assert_cmpuint (g_io_error_from_errno (ENOTRECOVERABLE), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef ERFKILL
g_assert_cmpuint (g_io_error_from_errno (ERFKILL), ==,
G_IO_ERROR_FAILED);
#endif
#ifdef EHWPOISON
g_assert_cmpuint (g_io_error_from_errno (EHWPOISON), ==,
G_IO_ERROR_FAILED);
#endif
}
static void
test_error_from_file_error (void)
{
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*should not be reached*");
g_assert_cmpuint (g_io_error_from_file_error (-1), ==,
G_IO_ERROR_FAILED);
g_test_assert_expected_messages ();
g_assert_cmpuint (g_io_error_from_file_error (G_FILE_ERROR_EXIST), ==,
G_IO_ERROR_EXISTS);
g_assert_cmpuint (g_io_error_from_file_error (G_FILE_ERROR_ISDIR), ==,
G_IO_ERROR_IS_DIRECTORY);
g_assert_cmpuint (g_io_error_from_file_error (G_FILE_ERROR_ACCES), ==,
G_IO_ERROR_PERMISSION_DENIED);
g_assert_cmpuint (g_io_error_from_file_error (G_FILE_ERROR_NAMETOOLONG), ==,
G_IO_ERROR_FILENAME_TOO_LONG);
g_assert_cmpuint (g_io_error_from_file_error (G_FILE_ERROR_NOENT), ==,
G_IO_ERROR_NOT_FOUND);
g_assert_cmpuint (g_io_error_from_file_error (G_FILE_ERROR_NOTDIR), ==,
G_IO_ERROR_NOT_DIRECTORY);
g_assert_cmpuint (g_io_error_from_file_error (G_FILE_ERROR_NXIO), ==,
G_IO_ERROR_NOT_REGULAR_FILE);
g_assert_cmpuint (g_io_error_from_file_error (G_FILE_ERROR_NODEV), ==,
G_IO_ERROR_NO_SUCH_DEVICE);
g_assert_cmpuint (g_io_error_from_file_error (G_FILE_ERROR_ROFS), ==,
G_IO_ERROR_READ_ONLY);
g_assert_cmpuint (g_io_error_from_file_error (G_FILE_ERROR_TXTBSY), ==,
G_IO_ERROR_BUSY);
g_assert_cmpuint (g_io_error_from_file_error (G_FILE_ERROR_LOOP), ==,
G_IO_ERROR_TOO_MANY_LINKS);
g_assert_cmpuint (g_io_error_from_file_error (G_FILE_ERROR_NOSPC), ==,
G_IO_ERROR_NO_SPACE);
g_assert_cmpuint (g_io_error_from_file_error (G_FILE_ERROR_NOMEM), ==,
G_IO_ERROR_NO_SPACE);
g_assert_cmpuint (g_io_error_from_file_error (G_FILE_ERROR_MFILE), ==,
G_IO_ERROR_TOO_MANY_OPEN_FILES);
g_assert_cmpuint (g_io_error_from_file_error (G_FILE_ERROR_NFILE), ==,
G_IO_ERROR_TOO_MANY_OPEN_FILES);
g_assert_cmpuint (g_io_error_from_file_error (G_FILE_ERROR_INVAL), ==,
G_IO_ERROR_INVALID_ARGUMENT);
g_assert_cmpuint (g_io_error_from_file_error (G_FILE_ERROR_PIPE), ==,
G_IO_ERROR_BROKEN_PIPE);
g_assert_cmpuint (g_io_error_from_file_error (G_FILE_ERROR_AGAIN), ==,
G_IO_ERROR_WOULD_BLOCK);
g_assert_cmpuint (g_io_error_from_file_error (G_FILE_ERROR_PERM), ==,
G_IO_ERROR_PERMISSION_DENIED);
g_assert_cmpuint (g_io_error_from_file_error (G_FILE_ERROR_NOSYS), ==,
G_IO_ERROR_NOT_SUPPORTED);
g_assert_cmpuint (g_io_error_from_file_error (G_FILE_ERROR_BADF), ==,
G_IO_ERROR_FAILED);
g_assert_cmpuint (g_io_error_from_file_error (G_FILE_ERROR_FAILED), ==,
G_IO_ERROR_FAILED);
g_assert_cmpuint (g_io_error_from_file_error (G_FILE_ERROR_FAULT), ==,
G_IO_ERROR_FAILED);
g_assert_cmpuint (g_io_error_from_file_error (G_FILE_ERROR_INTR), ==,
G_IO_ERROR_FAILED);
g_assert_cmpuint (g_io_error_from_file_error (G_FILE_ERROR_IO), ==,
G_IO_ERROR_FAILED);
}
static void
test_error_from_win32_error (void)
{
#ifdef G_OS_WIN32
g_assert_cmpint (g_io_error_from_win32_error (-1), ==, G_IO_ERROR_FAILED);
g_assert_cmpint (g_io_error_from_win32_error (WSAEADDRINUSE), ==,
G_IO_ERROR_ADDRESS_IN_USE);
g_assert_cmpint (g_io_error_from_win32_error (WSAEWOULDBLOCK), ==,
G_IO_ERROR_WOULD_BLOCK);
g_assert_cmpint (g_io_error_from_win32_error (WSAEACCES), ==,
G_IO_ERROR_PERMISSION_DENIED);
g_assert_cmpint (g_io_error_from_win32_error (WSA_INVALID_HANDLE), ==,
G_IO_ERROR_INVALID_ARGUMENT);
g_assert_cmpint (g_io_error_from_win32_error (WSA_INVALID_PARAMETER), ==,
G_IO_ERROR_INVALID_ARGUMENT);
g_assert_cmpint (g_io_error_from_win32_error (WSAEINVAL), ==,
G_IO_ERROR_INVALID_ARGUMENT);
g_assert_cmpint (g_io_error_from_win32_error (WSAEBADF), ==,
G_IO_ERROR_INVALID_ARGUMENT);
g_assert_cmpint (g_io_error_from_win32_error (WSAENOTSOCK), ==,
G_IO_ERROR_INVALID_ARGUMENT);
g_assert_cmpint (g_io_error_from_win32_error (WSAEPROTONOSUPPORT), ==,
G_IO_ERROR_NOT_SUPPORTED);
g_assert_cmpint (g_io_error_from_win32_error (WSAECANCELLED), ==,
G_IO_ERROR_CANCELLED);
g_assert_cmpint (g_io_error_from_win32_error (WSAESOCKTNOSUPPORT), ==,
G_IO_ERROR_NOT_SUPPORTED);
g_assert_cmpint (g_io_error_from_win32_error (WSAEOPNOTSUPP), ==,
G_IO_ERROR_NOT_SUPPORTED);
g_assert_cmpint (g_io_error_from_win32_error (WSAEPFNOSUPPORT), ==,
G_IO_ERROR_NOT_SUPPORTED);
g_assert_cmpint (g_io_error_from_win32_error (WSAEAFNOSUPPORT), ==,
G_IO_ERROR_NOT_SUPPORTED);
g_assert_cmpint (g_io_error_from_win32_error (WSAECONNRESET), ==,
G_IO_ERROR_CONNECTION_CLOSED);
g_assert_cmpint (g_io_error_from_win32_error (WSAENETRESET), ==,
G_IO_ERROR_CONNECTION_CLOSED);
g_assert_cmpint (g_io_error_from_win32_error (WSAESHUTDOWN), ==,
G_IO_ERROR_CONNECTION_CLOSED);
g_assert_cmpint (g_io_error_from_win32_error (WSAEHOSTUNREACH), ==,
G_IO_ERROR_HOST_UNREACHABLE);
g_assert_cmpint (g_io_error_from_win32_error (WSAENETUNREACH), ==,
G_IO_ERROR_NETWORK_UNREACHABLE);
g_assert_cmpint (g_io_error_from_win32_error (WSAECONNREFUSED), ==,
G_IO_ERROR_CONNECTION_REFUSED);
g_assert_cmpint (g_io_error_from_win32_error (WSAETIMEDOUT), ==,
G_IO_ERROR_TIMED_OUT);
g_assert_cmpint (g_io_error_from_win32_error (WSAENOTCONN), ==,
G_IO_ERROR_NOT_CONNECTED);
g_assert_cmpint (g_io_error_from_win32_error (ERROR_PIPE_LISTENING), ==,
G_IO_ERROR_NOT_CONNECTED);
g_assert_cmpint (g_io_error_from_win32_error (WSAEMSGSIZE), ==,
G_IO_ERROR_MESSAGE_TOO_LARGE);
#else
g_test_skip ("Windows error codes can only be checked on Windows");
#endif /* G_OS_WIN32 */
}
int
main (int argc,
char *argv[])
{
g_setenv ("LC_ALL", "C", TRUE);
g_test_init (&argc, &argv, G_TEST_OPTION_ISOLATE_DIRS, NULL);
g_test_add_func ("/error/from-errno", test_error_from_errno);
g_test_add_func ("/error/from-file-error", test_error_from_file_error);
g_test_add_func ("/error/from-win32-error", test_error_from_win32_error);
return g_test_run ();
}

View File

@ -8,6 +8,12 @@
#include <sys/stat.h>
#endif
typedef struct
{
GMainLoop *loop;
GError **error;
} AsyncErrorData;
static void
test_basic_for_file (GFile *file,
const gchar *suffix)
@ -852,6 +858,18 @@ test_replace_symlink (void)
g_test_message ("Using temporary directory %s", tmpdir_path);
g_free (tmpdir_path);
source_file = g_file_get_child (tmpdir, "source");
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*symlink_value*failed*");
g_assert_false (g_file_make_symbolic_link (source_file, NULL, NULL, &local_error));
g_assert_no_error (local_error);
g_test_assert_expected_messages ();
g_assert_false (g_file_make_symbolic_link (source_file, "", NULL, &local_error));
g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
g_clear_object (&source_file);
g_clear_error (&local_error);
/* Create symlink `source` which points to `target`. */
source_file = g_file_get_child (tmpdir, "source");
target_file = g_file_get_child (tmpdir, "target");
@ -1958,6 +1976,200 @@ test_replace (gconstpointer test_data)
#endif
}
static void
on_new_tmp_done (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
GFile *file;
GFile *parent;
GFileInfo *info;
GFileIOStream *iostream;
GError *error = NULL;
GMainLoop *loop = user_data;
gchar *basename;
gchar *parent_path;
g_assert_null (object);
file = g_file_new_tmp_finish (result, &iostream, &error);
g_assert_no_error (error);
g_assert_true (g_file_query_exists (file, NULL));
basename = g_file_get_basename (file);
g_assert_true (g_str_has_prefix (basename, "g_file_new_tmp_async_"));
info = g_file_io_stream_query_info (iostream, G_FILE_ATTRIBUTE_STANDARD_TYPE,
NULL, &error);
g_assert_no_error (error);
g_assert_cmpuint (g_file_info_get_file_type (info), ==, G_FILE_TYPE_REGULAR);
g_io_stream_close (G_IO_STREAM (iostream), NULL, &error);
g_assert_no_error (error);
parent = g_file_get_parent (file);
parent_path = g_file_get_path (parent);
g_assert_cmpstr (g_get_tmp_dir (), ==, parent_path);
g_main_loop_quit (loop);
g_object_unref (file);
g_object_unref (parent);
g_object_unref (iostream);
g_object_unref (info);
g_free (basename);
g_free (parent_path);
}
static void
on_new_tmp_error (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
GFileIOStream *iostream = (GFileIOStream*) &on_new_tmp_error;
AsyncErrorData *error_data = user_data;
g_assert_null (object);
g_assert_null (g_file_new_tmp_finish (result, &iostream, error_data->error));
g_assert_nonnull (error_data->error);
g_assert_null (iostream);
g_main_loop_quit (error_data->loop);
}
static void
test_async_new_tmp (void)
{
GMainLoop *loop;
GError *error = NULL;
GCancellable *cancellable;
AsyncErrorData error_data = { .error = &error };
loop = g_main_loop_new (NULL, TRUE);
error_data.loop = loop;
g_file_new_tmp_async ("g_file_new_tmp_async_XXXXXX",
G_PRIORITY_DEFAULT, NULL,
on_new_tmp_done, loop);
g_main_loop_run (loop);
g_file_new_tmp_async ("g_file_new_tmp_async_invalid_template",
G_PRIORITY_DEFAULT, NULL,
on_new_tmp_error, &error_data);
g_main_loop_run (loop);
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED);
g_clear_error (&error);
cancellable = g_cancellable_new ();
g_file_new_tmp_async ("g_file_new_tmp_async_cancelled_XXXXXX",
G_PRIORITY_DEFAULT, cancellable,
on_new_tmp_error, &error_data);
g_cancellable_cancel (cancellable);
g_main_loop_run (loop);
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
g_clear_object (&cancellable);
g_clear_error (&error);
g_main_loop_unref (loop);
}
static void
on_new_tmp_dir_done (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
GFile *file;
GFile *parent;
GFileInfo *info;
GError *error = NULL;
GMainLoop *loop = user_data;
gchar *basename;
gchar *parent_path;
g_assert_null (object);
file = g_file_new_tmp_dir_finish (result, &error);
g_assert_no_error (error);
g_assert_true (g_file_query_exists (file, NULL));
basename = g_file_get_basename (file);
g_assert_true (g_str_has_prefix (basename, "g_file_new_tmp_dir_async_"));
info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_TYPE,
G_FILE_QUERY_INFO_NONE, NULL, &error);
g_assert_no_error (error);
g_assert_cmpuint (g_file_info_get_file_type (info), ==, G_FILE_TYPE_DIRECTORY);
parent = g_file_get_parent (file);
parent_path = g_file_get_path (parent);
g_assert_cmpstr (g_get_tmp_dir (), ==, parent_path);
g_main_loop_quit (loop);
g_object_unref (file);
g_object_unref (parent);
g_object_unref (info);
g_free (basename);
g_free (parent_path);
}
static void
on_new_tmp_dir_error (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
AsyncErrorData *error_data = user_data;
g_assert_null (object);
g_assert_null (g_file_new_tmp_dir_finish (result, error_data->error));
g_assert_nonnull (error_data->error);
g_main_loop_quit (error_data->loop);
}
static void
test_async_new_tmp_dir (void)
{
GMainLoop *loop;
GError *error = NULL;
GCancellable *cancellable;
AsyncErrorData error_data = { .error = &error };
loop = g_main_loop_new (NULL, TRUE);
error_data.loop = loop;
g_file_new_tmp_dir_async ("g_file_new_tmp_dir_async_XXXXXX",
G_PRIORITY_DEFAULT, NULL,
on_new_tmp_dir_done, loop);
g_main_loop_run (loop);
g_file_new_tmp_dir_async ("g_file_new_tmp_dir_async",
G_PRIORITY_DEFAULT, NULL,
on_new_tmp_dir_error, &error_data);
g_main_loop_run (loop);
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED);
g_clear_error (&error);
cancellable = g_cancellable_new ();
g_file_new_tmp_dir_async ("g_file_new_tmp_dir_async_cancelled_XXXXXX",
G_PRIORITY_DEFAULT, cancellable,
on_new_tmp_dir_error, &error_data);
g_cancellable_cancel (cancellable);
g_main_loop_run (loop);
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
g_clear_object (&cancellable);
g_clear_error (&error);
g_main_loop_unref (loop);
}
static void
on_file_deleted (GObject *object,
GAsyncResult *result,
@ -2000,6 +2212,133 @@ test_async_delete (void)
g_object_unref (file);
}
static void
on_symlink_done (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
GFile *file = (GFile *) object;
GError *error = NULL;
GMainLoop *loop = user_data;
g_assert_true (g_file_make_symbolic_link_finish (file, result, &error));
g_assert_no_error (error);
g_main_loop_quit (loop);
}
static void
on_symlink_error (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
GFile *file = (GFile *) object;
GError *error = NULL;
AsyncErrorData *data = user_data;
g_assert_false (g_file_make_symbolic_link_finish (file, result, &error));
g_assert_nonnull (error);
g_propagate_error (data->error, g_steal_pointer (&error));
g_main_loop_quit (data->loop);
}
static void
test_async_make_symlink (void)
{
GFile *link;
GFile *parent_dir;
GFile *target;
GFileInfo *link_info;
GFileIOStream *iostream;
GError *error = NULL;
GCancellable *cancellable;
GMainLoop *loop;
AsyncErrorData error_data = {0};
gchar *tmpdir_path;
gchar *target_path;
target = g_file_new_tmp ("g_file_symlink_target_XXXXXX", &iostream, &error);
g_assert_no_error (error);
g_io_stream_close ((GIOStream *) iostream, NULL, &error);
g_assert_no_error (error);
g_object_unref (iostream);
g_assert_true (g_file_query_exists (target, NULL));
loop = g_main_loop_new (NULL, TRUE);
error_data.loop = loop;
error_data.error = &error;
tmpdir_path = g_dir_make_tmp ("g_file_symlink_XXXXXX", &error);
g_assert_no_error (error);
parent_dir = g_file_new_for_path (tmpdir_path);
g_assert_true (g_file_query_exists (parent_dir, NULL));
link = g_file_get_child (parent_dir, "symlink");
g_assert_false (g_file_query_exists (link, NULL));
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*symlink_value*failed*");
g_file_make_symbolic_link_async (link, NULL,
G_PRIORITY_DEFAULT, NULL,
on_symlink_done, loop);
g_test_assert_expected_messages ();
g_file_make_symbolic_link_async (link, "",
G_PRIORITY_DEFAULT, NULL,
on_symlink_error, &error_data);
g_main_loop_run (loop);
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
g_clear_error (&error);
target_path = g_file_get_path (target);
g_file_make_symbolic_link_async (link, target_path,
G_PRIORITY_DEFAULT, NULL,
on_symlink_done, loop);
g_main_loop_run (loop);
g_assert_true (g_file_query_exists (link, NULL));
link_info = g_file_query_info (link,
G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK ","
G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET,
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
NULL,
&error);
g_assert_no_error (error);
g_assert_true (g_file_info_get_is_symlink (link_info));
g_assert_cmpstr (target_path, ==, g_file_info_get_symlink_target (link_info));
/* Try creating it again, it fails */
g_file_make_symbolic_link_async (link, target_path,
G_PRIORITY_DEFAULT, NULL,
on_symlink_error, &error_data);
g_main_loop_run (loop);
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_EXISTS);
g_clear_error (&error);
cancellable = g_cancellable_new ();
g_file_make_symbolic_link_async (link, target_path,
G_PRIORITY_DEFAULT, cancellable,
on_symlink_error, &error_data);
g_cancellable_cancel (cancellable);
g_main_loop_run (loop);
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
g_clear_error (&error);
g_clear_object (&cancellable);
g_main_loop_unref (loop);
g_object_unref (target);
g_object_unref (parent_dir);
g_object_unref (link);
g_object_unref (link_info);
g_free (tmpdir_path);
g_free (target_path);
}
static void
test_copy_preserve_mode (void)
{
@ -3125,6 +3464,307 @@ test_move_async (void)
g_free (destination_path);
}
static GAppInfo *
create_command_line_app_info (const char *name,
const char *command_line,
const char *default_for_type)
{
GAppInfo *info;
GError *error = NULL;
info = g_app_info_create_from_commandline (command_line,
name,
G_APP_INFO_CREATE_NONE,
&error);
g_assert_no_error (error);
g_app_info_set_as_default_for_type (info, default_for_type, &error);
g_assert_no_error (error);
return g_steal_pointer (&info);
}
static void
test_query_default_handler_uri (void)
{
GError *error = NULL;
GAppInfo *info;
GAppInfo *default_info;
GFile *file;
GFile *invalid_file;
#ifdef G_OS_WIN32
g_test_skip ("Default URI handlers are not currently supported on Windows");
return;
#endif
info = create_command_line_app_info ("Gio File Handler", "true",
"x-scheme-handler/gio-file");
g_assert_true (G_IS_APP_INFO (info));
file = g_file_new_for_uri ("gio-file://hello-gio!");
default_info = g_file_query_default_handler (file, NULL, &error);
g_assert_no_error (error);
g_assert_true (g_app_info_equal (default_info, info));
invalid_file = g_file_new_for_uri ("gio-file-INVALID://goodbye-gio!");
g_assert_null (g_file_query_default_handler (invalid_file, NULL, &error));
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
g_clear_error (&error);
g_app_info_remove_supports_type (info, "x-scheme-handler/gio-file", &error);
g_assert_no_error (error);
g_app_info_reset_type_associations ("x-scheme-handler/gio-file");
g_object_unref (default_info);
g_object_unref (info);
g_object_unref (file);
g_object_unref (invalid_file);
}
static void
test_query_default_handler_file (void)
{
GError *error = NULL;
GAppInfo *info;
GAppInfo *default_info;
GFile *text_file;
GFile *binary_file;
GFile *invalid_file;
GFileIOStream *iostream;
GOutputStream *output_stream;
const char buffer[] = "Text file!\n";
const guint8 binary_buffer[] = "\xde\xad\xbe\xff";
#ifdef G_OS_WIN32
g_test_skip ("Default URI handlers are not currently supported on Windows");
return;
#endif
text_file = g_file_new_tmp ("query-default-handler-XXXXXX", &iostream, &error);
g_assert_no_error (error);
output_stream = g_io_stream_get_output_stream (G_IO_STREAM (iostream));
g_output_stream_write_all (output_stream, buffer, G_N_ELEMENTS (buffer) - 1,
NULL, NULL, &error);
g_assert_no_error (error);
g_output_stream_close (output_stream, NULL, &error);
g_assert_no_error (error);
g_clear_object (&iostream);
info = create_command_line_app_info ("Text handler", "true", "text/plain");
g_assert_true (G_IS_APP_INFO (info));
default_info = g_file_query_default_handler (text_file, NULL, &error);
g_assert_no_error (error);
g_assert_true (g_app_info_equal (default_info, info));
invalid_file = g_file_new_for_path ("/hopefully/this-does-not-exists");
g_assert_null (g_file_query_default_handler (invalid_file, NULL, &error));
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND);
g_clear_error (&error);
binary_file = g_file_new_tmp ("query-default-handler-bin-XXXXXX", &iostream, &error);
g_assert_no_error (error);
output_stream = g_io_stream_get_output_stream (G_IO_STREAM (iostream));
g_output_stream_write_all (output_stream, binary_buffer,
G_N_ELEMENTS (binary_buffer),
NULL, NULL, &error);
g_assert_no_error (error);
g_output_stream_close (output_stream, NULL, &error);
g_assert_no_error (error);
g_clear_object (&iostream);
g_assert_null (g_file_query_default_handler (binary_file, NULL, &error));
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
g_clear_error (&error);
g_app_info_remove_supports_type (info, "text/plain", &error);
g_assert_no_error (error);
g_app_info_reset_type_associations ("text/plain");
g_object_unref (default_info);
g_object_unref (info);
g_object_unref (text_file);
g_object_unref (binary_file);
g_object_unref (invalid_file);
}
typedef struct {
GMainLoop *loop;
GAppInfo *info;
GError *error;
} QueryDefaultHandlerData;
static void
on_query_default (GObject *source,
GAsyncResult *result,
gpointer user_data)
{
QueryDefaultHandlerData *data = user_data;
data->info = g_file_query_default_handler_finish (G_FILE (source), result,
&data->error);
g_main_loop_quit (data->loop);
}
static void
test_query_default_handler_file_async (void)
{
QueryDefaultHandlerData data = {0};
GCancellable *cancellable;
GAppInfo *info;
GFile *text_file;
GFile *binary_file;
GFile *invalid_file;
GFileIOStream *iostream;
GOutputStream *output_stream;
const char buffer[] = "Text file!\n";
const guint8 binary_buffer[] = "\xde\xad\xbe\xff";
GError *error = NULL;
#ifdef G_OS_WIN32
g_test_skip ("Default URI handlers are not currently supported on Windows");
return;
#endif
data.loop = g_main_loop_new (NULL, FALSE);
text_file = g_file_new_tmp ("query-default-handler-XXXXXX", &iostream, &error);
g_assert_no_error (error);
output_stream = g_io_stream_get_output_stream (G_IO_STREAM (iostream));
g_output_stream_write_all (output_stream, buffer, G_N_ELEMENTS (buffer) - 1,
NULL, NULL, &error);
g_assert_no_error (error);
g_output_stream_close (output_stream, NULL, &error);
g_assert_no_error (error);
g_clear_object (&iostream);
info = create_command_line_app_info ("Text handler", "true", "text/plain");
g_assert_true (G_IS_APP_INFO (info));
g_file_query_default_handler_async (text_file, G_PRIORITY_DEFAULT,
NULL, on_query_default,
&data);
g_main_loop_run (data.loop);
g_assert_no_error (data.error);
g_assert_true (g_app_info_equal (data.info, info));
g_clear_object (&data.info);
invalid_file = g_file_new_for_path ("/hopefully/this/.file/does-not-exists");
g_file_query_default_handler_async (invalid_file, G_PRIORITY_DEFAULT,
NULL, on_query_default,
&data);
g_main_loop_run (data.loop);
g_assert_null (data.info);
g_assert_error (data.error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND);
g_clear_error (&data.error);
cancellable = g_cancellable_new ();
g_file_query_default_handler_async (text_file, G_PRIORITY_DEFAULT,
cancellable, on_query_default,
&data);
g_cancellable_cancel (cancellable);
g_main_loop_run (data.loop);
g_assert_null (data.info);
g_assert_error (data.error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
g_clear_error (&data.error);
binary_file = g_file_new_tmp ("query-default-handler-bin-XXXXXX", &iostream, &error);
g_assert_no_error (error);
output_stream = g_io_stream_get_output_stream (G_IO_STREAM (iostream));
g_output_stream_write_all (output_stream, binary_buffer,
G_N_ELEMENTS (binary_buffer),
NULL, NULL, &error);
g_assert_no_error (error);
g_output_stream_close (output_stream, NULL, &error);
g_assert_no_error (error);
g_clear_object (&iostream);
g_file_query_default_handler_async (binary_file, G_PRIORITY_DEFAULT,
NULL, on_query_default,
&data);
g_main_loop_run (data.loop);
g_assert_null (data.info);
g_assert_error (data.error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
g_clear_error (&data.error);
g_app_info_remove_supports_type (info, "text/plain", &error);
g_assert_no_error (error);
g_app_info_reset_type_associations ("text/plain");
g_main_loop_unref (data.loop);
g_object_unref (info);
g_object_unref (text_file);
g_object_unref (binary_file);
g_object_unref (invalid_file);
}
static void
test_query_default_handler_uri_async (void)
{
QueryDefaultHandlerData data = {0};
GCancellable *cancellable;
GAppInfo *info;
GFile *file;
GFile *invalid_file;
#ifdef G_OS_WIN32
g_test_skip ("Default URI handlers are not currently supported on Windows");
return;
#endif
info = create_command_line_app_info ("Gio File Handler", "true",
"x-scheme-handler/gio-file");
g_assert_true (G_IS_APP_INFO (info));
data.loop = g_main_loop_new (NULL, FALSE);
file = g_file_new_for_uri ("gio-file://hello-gio!");
g_file_query_default_handler_async (file, G_PRIORITY_DEFAULT,
NULL, on_query_default,
&data);
g_main_loop_run (data.loop);
g_assert_no_error (data.error);
g_assert_true (g_app_info_equal (data.info, info));
g_clear_object (&data.info);
invalid_file = g_file_new_for_uri ("gio-file-INVALID://goodbye-gio!");
g_file_query_default_handler_async (invalid_file, G_PRIORITY_DEFAULT,
NULL, on_query_default,
&data);
g_main_loop_run (data.loop);
g_assert_null (data.info);
g_assert_error (data.error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
g_clear_error (&data.error);
cancellable = g_cancellable_new ();
g_file_query_default_handler_async (file, G_PRIORITY_DEFAULT,
cancellable, on_query_default,
&data);
g_cancellable_cancel (cancellable);
g_main_loop_run (data.loop);
g_assert_null (data.info);
g_assert_error (data.error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
g_clear_error (&data.error);
g_app_info_remove_supports_type (info, "x-scheme-handler/gio-file", &data.error);
g_assert_no_error (data.error);
g_app_info_reset_type_associations ("x-scheme-handler/gio-file");
g_main_loop_unref (data.loop);
g_object_unref (info);
g_object_unref (file);
g_object_unref (invalid_file);
}
int
main (int argc, char *argv[])
{
@ -3150,7 +3790,10 @@ main (int argc, char *argv[])
g_test_add_func ("/file/replace-symlink/using-etag", test_replace_symlink_using_etag);
g_test_add_data_func ("/file/replace/write-only", GUINT_TO_POINTER (FALSE), test_replace);
g_test_add_data_func ("/file/replace/read-write", GUINT_TO_POINTER (TRUE), test_replace);
g_test_add_func ("/file/async-new-tmp", test_async_new_tmp);
g_test_add_func ("/file/async-new-tmp-dir", test_async_new_tmp_dir);
g_test_add_func ("/file/async-delete", test_async_delete);
g_test_add_func ("/file/async-make-symlink", test_async_make_symlink);
g_test_add_func ("/file/copy-preserve-mode", test_copy_preserve_mode);
g_test_add_func ("/file/measure", test_measure);
g_test_add_func ("/file/measure-async", test_measure_async);
@ -3169,6 +3812,10 @@ main (int argc, char *argv[])
g_test_add_func ("/file/writev/async_all-cancellation", test_writev_async_all_cancellation);
g_test_add_func ("/file/build-attribute-list-for-copy", test_build_attribute_list_for_copy);
g_test_add_func ("/file/move_async", test_move_async);
g_test_add_func ("/file/query-default-handler-file", test_query_default_handler_file);
g_test_add_func ("/file/query-default-handler-file-async", test_query_default_handler_file_async);
g_test_add_func ("/file/query-default-handler-uri", test_query_default_handler_uri);
g_test_add_func ("/file/query-default-handler-uri-async", test_query_default_handler_uri_async);
return g_test_run ();
}

View File

@ -63,6 +63,7 @@ gio_tests = {
},
'data-input-stream' : {},
'data-output-stream' : {},
'error': {},
'fileattributematcher' : {},
'filter-streams' : {},
'giomodule' : {