+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+
/* GIO - GLib Input, Output and Streaming Library
*
* Copyright (C) 2006-2007 Red Hat, Inc.
* Author: Alexander Larsson <alexl@redhat.com>
*/
-#include <config.h>
+#include "config.h"
+#ifdef HAVE_SPLICE
+#define _GNU_SOURCE
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#endif
#include <string.h>
#include <sys/types.h>
#ifdef HAVE_PWD_H
#include "gfile.h"
#include "gvfs.h"
#include "gioscheduler.h"
-#include <glocalfile.h>
#include "gsimpleasyncresult.h"
#include "gfileattribute-priv.h"
+#include "gfiledescriptorbased.h"
#include "gpollfilemonitor.h"
+#include "gappinfo.h"
+#include "gfileinputstream.h"
+#include "gfileoutputstream.h"
+#include "gcancellable.h"
+#include "gasyncresult.h"
+#include "gioerror.h"
#include "glibintl.h"
#include "gioalias.h"
/**
* SECTION:gfile
* @short_description: File and Directory Handling
- * @include: gio.h
+ * @include: gio/gio.h
* @see_also: #GFileInfo, #GFileEnumerator
*
* #GFile is a high level abstraction for manipulating files on a
* virtual file system. #GFile<!-- -->s are lightweight, immutable
* objects that do no I/O upon creation. It is necessary to understand that
- * #GFile objects do not represent files, merely a handle to a file. All
- * file I/O is implemented as streaming operations (see #GInputStream and
+ * #GFile objects do not represent files, merely an identifier for a file. All
+ * file content I/O is implemented as streaming operations (see #GInputStream and
* #GOutputStream).
- *
+ *
* To construct a #GFile, you can use:
* g_file_new_for_path() if you have a path.
* g_file_new_for_uri() if you have a URI.
* g_file_new_for_commandline_arg() for a command line argument.
- *
- * You can move through the file system with #GFile handles with
- * g_file_get_parent() to get a handle to the parent directory.
- * g_file_get_child() to get a handle to a child within a directory.
- * g_file_resolve_relative_path() to resolve a relative path between
- * two #GFile<!-- -->s.
+ * g_file_parse_name() from a utf8 string gotten from g_file_get_parse_name().
+ *
+ * One way to think of a #GFile is as an abstraction of a pathname. For normal
+ * files the system pathname is what is stored internally, but as #GFile<!-- -->s
+ * are extensible it could also be something else that corresponds to a pathname
+ * in a userspace implementation of a filesystem.
+ *
+ * #GFile<!-- -->s make up hierarchies of directories and files that correspond to the
+ * files on a filesystem. You can move through the file system with #GFile using
+ * g_file_get_parent() to get an identifier for the parent directory, g_file_get_child()
+ * to get a child within a directory, g_file_resolve_relative_path() to resolve a relative
+ * path between two #GFile<!-- -->s. There can be multiple hierarchies, so you may not
+ * end up at the same root if you repeatedly call g_file_get_parent() on two different
+ * files.
+ *
+ * All #GFile<!-- -->s have a basename (get with g_file_get_basename()). These names
+ * are byte strings that are used to identify the file on the filesystem (relative to
+ * its parent directory) and there is no guarantees that they have any particular charset
+ * encoding or even make any sense at all. If you want to use filenames in a user
+ * interface you should use the display name that you can get by requesting the
+ * %G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME attribute with g_file_query_info().
+ * This is guaranteed to be in utf8 and can be used in a user interface. But always
+ * store the real basename or the #GFile to use to actually access the file, because
+ * there is no way to go from a display name to the actual name.
+ *
+ * Using #GFile as an identifier has the same weaknesses as using a path in that
+ * there may be multiple aliases for the same file. For instance, hard or
+ * soft links may cause two different #GFile<!-- -->s to refer to the same file.
+ * Other possible causes for aliases are: case insensitive filesystems, short
+ * and long names on Fat/NTFS, or bind mounts in Linux. If you want to check if
+ * two #GFile<!-- -->s point to the same file you can query for the
+ * %G_FILE_ATTRIBUTE_ID_FILE attribute. Note that #GFile does some trivial
+ * canonicalization of pathnames passed in, so that trivial differences in the
+ * path string used at creation (duplicated slashes, slash at end of path, "."
+ * or ".." path segments, etc) does not create different #GFile<!-- -->s.
*
* Many #GFile operations have both synchronous and asynchronous versions
* to suit your application. Asynchronous versions of synchronous functions
* simply have _async() appended to their function names. The asynchronous
* I/O functions call a #GAsyncReadyCallback which is then used to finalize
* the operation, producing a GAsyncResult which is then passed to the
- * function's matching _finish()
- * operation.
+ * function's matching _finish() operation.
*
* Some #GFile operations do not have synchronous analogs, as they may
* take a very long time to finish, and blocking may leave an application
* unusable. Notable cases include:
* g_file_mount_mountable() to mount a mountable file.
- * g_file_unmount_mountable() to unmount a mountable file.
- * g_file_eject_mountable() to eject a mountable file.
+ * g_file_unmount_mountable_with_operation() to unmount a mountable file.
+ * g_file_eject_mountable_with_operation() to eject a mountable file.
*
* <para id="gfile-etag"><indexterm><primary>entity tag</primary></indexterm>
* One notable feature of #GFile<!-- -->s are entity tags, or "etags" for
* </para>
**/
-static void g_file_base_init (gpointer g_class);
-static void g_file_class_init (gpointer g_class,
- gpointer class_data);
-
static void g_file_real_query_info_async (GFile *file,
const char *attributes,
GFileQueryInfoFlags flags,
static GFileInfo * g_file_real_query_info_finish (GFile *file,
GAsyncResult *res,
GError **error);
+static void g_file_real_query_filesystem_info_async (GFile *file,
+ const char *attributes,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+static GFileInfo * g_file_real_query_filesystem_info_finish (GFile *file,
+ GAsyncResult *res,
+ GError **error);
static void g_file_real_enumerate_children_async (GFile *file,
const char *attributes,
GFileQueryInfoFlags flags,
static GFileOutputStream *g_file_real_replace_finish (GFile *file,
GAsyncResult *res,
GError **error);
+static void g_file_real_open_readwrite_async (GFile *file,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+static GFileIOStream * g_file_real_open_readwrite_finish (GFile *file,
+ GAsyncResult *res,
+ GError **error);
+static void g_file_real_create_readwrite_async (GFile *file,
+ GFileCreateFlags flags,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+static GFileIOStream * g_file_real_create_readwrite_finish (GFile *file,
+ GAsyncResult *res,
+ GError **error);
+static void g_file_real_replace_readwrite_async (GFile *file,
+ const char *etag,
+ gboolean make_backup,
+ GFileCreateFlags flags,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+static GFileIOStream * g_file_real_replace_readwrite_finish (GFile *file,
+ GAsyncResult *res,
+ GError **error);
static gboolean g_file_real_set_attributes_from_info (GFile *file,
GFileInfo *info,
GFileQueryInfoFlags flags,
GAsyncResult *res,
GError **error);
-GType
-g_file_get_type (void)
-{
- static GType file_type = 0;
-
- if (! file_type)
- {
- static const GTypeInfo file_info =
- {
- sizeof (GFileIface), /* class_size */
- g_file_base_init, /* base_init */
- NULL, /* base_finalize */
- g_file_class_init,
- NULL, /* class_finalize */
- NULL, /* class_data */
- 0,
- 0, /* n_preallocs */
- NULL
- };
-
- file_type =
- g_type_register_static (G_TYPE_INTERFACE, I_("GFile"),
- &file_info, 0);
-
- g_type_interface_add_prerequisite (file_type, G_TYPE_OBJECT);
- }
-
- return file_type;
-}
+typedef GFileIface GFileInterface;
+G_DEFINE_INTERFACE (GFile, g_file, G_TYPE_OBJECT)
static void
-g_file_class_init (gpointer g_class,
- gpointer class_data)
+g_file_default_init (GFileIface *iface)
{
- GFileIface *iface = g_class;
-
iface->enumerate_children_async = g_file_real_enumerate_children_async;
iface->enumerate_children_finish = g_file_real_enumerate_children_finish;
iface->set_display_name_async = g_file_real_set_display_name_async;
iface->set_display_name_finish = g_file_real_set_display_name_finish;
iface->query_info_async = g_file_real_query_info_async;
iface->query_info_finish = g_file_real_query_info_finish;
+ iface->query_filesystem_info_async = g_file_real_query_filesystem_info_async;
+ iface->query_filesystem_info_finish = g_file_real_query_filesystem_info_finish;
iface->set_attributes_async = g_file_real_set_attributes_async;
iface->set_attributes_finish = g_file_real_set_attributes_finish;
iface->read_async = g_file_real_read_async;
iface->create_finish = g_file_real_create_finish;
iface->replace_async = g_file_real_replace_async;
iface->replace_finish = g_file_real_replace_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;
+ iface->create_readwrite_finish = g_file_real_create_readwrite_finish;
+ iface->replace_readwrite_async = g_file_real_replace_readwrite_async;
+ iface->replace_readwrite_finish = g_file_real_replace_readwrite_finish;
iface->find_enclosing_mount_async = g_file_real_find_enclosing_mount_async;
iface->find_enclosing_mount_finish = g_file_real_find_enclosing_mount_finish;
iface->set_attributes_from_info = g_file_real_set_attributes_from_info;
iface->copy_finish = g_file_real_copy_finish;
}
-static void
-g_file_base_init (gpointer g_class)
-{
-}
-
/**
* g_file_is_native:
* Gets the base name (the last component of the path) for a given #GFile.
*
* If called for the top level of a system (such as the filesystem root
- * or a uri like sftp://host/ it will return a single directory separator
+ * or a uri like sftp://host/) it will return a single directory separator
* (and on Windows, possibly a drive letter).
*
+ * The base name is a byte string (*not* UTF-8). It has no defined encoding
+ * or rules other than it may not contain zero bytes. If you want to use
+ * filenames in a user interface you should use the display name that you
+ * can get by requesting the %G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME
+ * attribute with g_file_query_info().
+ *
* This call does no blocking i/o.
*
* Returns: string containing the #GFile's base name, or %NULL
* g_file_parse_name().
*
* This is generally used to show the #GFile as a nice
- * string in a user interface, like in a location entry.
+ * full-pathname kind of string in a user interface,
+ * like in a location entry.
*
* For local files with names that can safely be converted
* to UTF8 the pathname is used, otherwise the IRI is used
*
* This call does no blocking i/o.
*
- * Returns: #GFile that is a duplicate of the given #GFile.
+ * Returns: a new #GFile that is a duplicate of the given #GFile.
**/
GFile *
g_file_dup (GFile *file)
* @file1: the first #GFile.
* @file2: the second #GFile.
*
- * Checks equality of two given #GFile<!-- -->s
+ * Checks equality of two given #GFile<!-- -->s. Note that two
+ * #GFile<!-- -->s that differ can still refer to the same
+ * file on the filesystem due to various forms of filename
+ * aliasing.
*
* This call does no blocking i/o.
*
*
* Returns: a #GFile structure to the parent of the given
* #GFile or %NULL if there is no parent.
+ * Free the returned object with g_object_unref().
**/
GFile *
g_file_get_parent (GFile *file)
}
/**
+ * g_file_has_parent:
+ * @file: input #GFile
+ * @parent: the parent to check for, or %NULL
+ *
+ * Checks if @file has a parent, and optionally, if it is @parent.
+ *
+ * If @parent is %NULL then this function returns %TRUE if @file has any
+ * parent at all. If @parent is non-%NULL then %TRUE is only returned
+ * if @file is a child of @parent.
+ *
+ * Returns: %TRUE if @file is a child of @parent (or any parent in the
+ * case that @parent is %NULL).
+ *
+ * Since: 2.24
+ **/
+gboolean
+g_file_has_parent (GFile *file,
+ GFile *parent)
+{
+ GFile *actual_parent;
+ gboolean result;
+
+ g_return_val_if_fail (G_IS_FILE (file), FALSE);
+ g_return_val_if_fail (parent == NULL || G_IS_FILE (parent), FALSE);
+
+ actual_parent = g_file_get_parent (file);
+
+ if (actual_parent != NULL)
+ {
+ if (parent != NULL)
+ result = g_file_equal (parent, actual_parent);
+ else
+ result = TRUE;
+
+ g_object_unref (actual_parent);
+ }
+ else
+ result = FALSE;
+
+ return result;
+}
+
+/**
* g_file_get_child:
* @file: input #GFile.
- * @name: string containing the child's name.
+ * @name: string containing the child's basename.
*
- * Gets a specific child of @file with name equal to @name.
+ * Gets a child of @file with basename equal to @name.
*
* Note that the file with that specific name might not exist, but
* you can still have a #GFile that points to it. You can use this
* This call does no blocking i/o.
*
* Returns: a #GFile to a child specified by @name.
+ * Free the returned object with g_object_unref().
**/
GFile *
g_file_get_child (GFile *file,
*
* Returns: a #GFile to the specified child, or
* %NULL if the display name couldn't be converted.
+ * Free the returned object with g_object_unref().
**/
GFile *
g_file_get_child_for_display_name (GFile *file,
}
/**
- * g_file_contains_file:
- * @parent: input #GFile.
- * @descendant: input #GFile.
- *
- * Checks whether @parent (recursively) contains the specified @descendant.
+ * g_file_has_prefix:
+ * @file: input #GFile.
+ * @prefix: input #GFile.
*
- * This call does no blocking i/o.
+ * Checks whether @file has the prefix specified by @prefix. In other word,
+ * if the names of inital elements of @file<!-- -->s pathname match @prefix.
+ * Only full pathname elements are matched, so a path like /foo is not
+ * considered a prefix of /foobar, only of /foo/bar.
*
- * Returns: %TRUE if the @descendant's parent, grandparent, etc is @parent. %FALSE otherwise.
+ * This call does no i/o, as it works purely on names. As such it can
+ * sometimes return %FALSE even if @file is inside a @prefix (from a
+ * filesystem point of view), because the prefix of @file is an alias
+ * of @prefix.
+ *
+ * Returns: %TRUE if the @files's parent, grandparent, etc is @prefix.
+ * %FALSE otherwise.
**/
gboolean
-g_file_contains_file (GFile *parent,
- GFile *descendant)
+g_file_has_prefix (GFile *file,
+ GFile *prefix)
{
GFileIface *iface;
- g_return_val_if_fail (G_IS_FILE (parent), FALSE);
- g_return_val_if_fail (G_IS_FILE (descendant), FALSE);
+ g_return_val_if_fail (G_IS_FILE (file), FALSE);
+ g_return_val_if_fail (G_IS_FILE (prefix), FALSE);
- if (G_TYPE_FROM_INSTANCE (parent) != G_TYPE_FROM_INSTANCE (descendant))
+ if (G_TYPE_FROM_INSTANCE (file) != G_TYPE_FROM_INSTANCE (prefix))
return FALSE;
- iface = G_FILE_GET_IFACE (parent);
+ iface = G_FILE_GET_IFACE (file);
- return (* iface->contains_file) (parent, descendant);
+ /* The vtable function differs in arg order since we're
+ using the old contains_file call */
+ return (* iface->prefix_matches) (prefix, file);
}
/**
* This call does no blocking i/o.
*
* Returns: string with the relative path from @descendant
- * to @parent, or %NULL if @descendant is not a descendant of @parent. The returned string should be freed with
- * g_free() when no longer needed.
+ * to @parent, or %NULL if @descendant doesn't have @parent as prefix.
+ * The returned string should be freed with g_free() when no longer needed.
**/
char *
g_file_get_relative_path (GFile *parent,
*
* Returns: #GFile to the resolved path. %NULL if @relative_path
* is %NULL or if @file is invalid.
+ * Free the returned object with g_object_unref().
**/
GFile *
g_file_resolve_relative_path (GFile *file,
* Other errors are possible too.
*
* Returns: A #GFileEnumerator if successful, %NULL on error.
+ * Free the returned object with g_object_unref().
**/
GFileEnumerator *
g_file_enumerate_children (GFile *file,
if (iface->enumerate_children == NULL)
{
- g_set_error (error, G_IO_ERROR,
- G_IO_ERROR_NOT_SUPPORTED,
- _("Operation not supported"));
+ g_set_error_literal (error, G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ _("Operation not supported"));
return NULL;
}
* See g_file_enumerate_children_async().
*
* Returns: a #GFileEnumerator or %NULL if an error occurred.
+ * Free the returned object with g_object_unref().
**/
GFileEnumerator *
g_file_enumerate_children_finish (GFile *file,
* Utility function to check if a particular file exists. This is
* implemented using g_file_query_info() and as such does blocking I/O.
*
- * Note that in many cases it is racy to first check for file existance
+ * Note that in many cases it is racy to first check for file existence
* and then execute something based on the outcome of that, because the
- * file might have been created or removed inbetween the operations. The
+ * file might have been created or removed in between the operations. The
* general approach to handling that is to not check, but just do the
* operation and handle the errors as they come.
*
* the file with g_file_create() which will either atomically create the file
* or fail with a G_IO_ERROR_EXISTS error.
*
- * However, in many cases an existance check is useful in a user
+ * However, in many cases an existence check is useful in a user
* interface, for instance to make a menu item sensitive/insensitive, so that
* you don't have to fool users that something is possible and then just show
* and error dialog. If you do this, you should make sure to also handle the
GCancellable *cancellable)
{
GFileInfo *info;
-
+
+ g_return_val_if_fail (G_IS_FILE(file), FALSE);
+
info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_TYPE,
- G_FILE_QUERY_INFO_NONE,
- cancellable, NULL);
+ G_FILE_QUERY_INFO_NONE, cancellable, NULL);
if (info != NULL)
{
g_object_unref (info);
}
/**
+ * g_file_query_file_type:
+ * @file: input #GFile.
+ * @flags: a set of #GFileQueryInfoFlags passed to g_file_query_info().
+ * @cancellable: optional #GCancellable object, %NULL to ignore.
+ *
+ * Utility function to inspect the #GFileType of a file. This is
+ * implemented using g_file_query_info() and as such does blocking I/O.
+ *
+ * The primary use case of this method is to check if a file is a regular file,
+ * directory, or symlink.
+ *
+ * Returns: The #GFileType of the file and #G_FILE_TYPE_UNKNOWN if the file
+ * does not exist
+ *
+ * Since: 2.18
+ */
+GFileType
+g_file_query_file_type (GFile *file,
+ GFileQueryInfoFlags flags,
+ GCancellable *cancellable)
+{
+ GFileInfo *info;
+ GFileType file_type;
+
+ g_return_val_if_fail (G_IS_FILE(file), G_FILE_TYPE_UNKNOWN);
+ info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_TYPE, flags,
+ cancellable, NULL);
+ if (info != NULL)
+ {
+ file_type = g_file_info_get_file_type (info);
+ g_object_unref (info);
+ }
+ else
+ file_type = G_FILE_TYPE_UNKNOWN;
+
+ return file_type;
+}
+
+/**
* g_file_query_info:
* @file: input #GFile.
* @attributes: an attribute query string.
* Other errors are possible too, and depend on what kind of filesystem the file is on.
*
* Returns: a #GFileInfo for the given @file, or %NULL on error.
+ * Free the returned object with g_object_unref().
**/
GFileInfo *
g_file_query_info (GFile *file,
if (iface->query_info == NULL)
{
- g_set_error (error, G_IO_ERROR,
- G_IO_ERROR_NOT_SUPPORTED,
- _("Operation not supported"));
+ g_set_error_literal (error, G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ _("Operation not supported"));
return NULL;
}
* See g_file_query_info_async().
*
* Returns: #GFileInfo for given @file or %NULL on error.
+ * Free the returned object with g_object_unref().
**/
GFileInfo *
g_file_query_info_finish (GFile *file,
* Other errors are possible too, and depend on what kind of filesystem the file is on.
*
* Returns: a #GFileInfo or %NULL if there was an error.
+ * Free the returned object with g_object_unref().
**/
GFileInfo *
g_file_query_filesystem_info (GFile *file,
if (iface->query_filesystem_info == NULL)
{
- g_set_error (error, G_IO_ERROR,
- G_IO_ERROR_NOT_SUPPORTED,
- _("Operation not supported"));
+ g_set_error_literal (error, G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ _("Operation not supported"));
return NULL;
}
}
/**
+ * g_file_query_filesystem_info_async:
+ * @file: input #GFile.
+ * @attributes: an attribute query string.
+ * @io_priority: the <link linkend="io-priority">I/O priority</link>
+ * of the request.
+ * @cancellable: 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 gets the requested information about the filesystem
+ * that the specified @file is on. The result is a #GFileInfo object
+ * that contains key-value attributes (such as type or size for the
+ * file).
+ *
+ * For more details, see g_file_query_filesystem_info() which is the
+ * synchronous version of this call.
+ *
+ * When the operation is finished, @callback will be called. You can
+ * then call g_file_query_info_finish() to get the result of the
+ * operation.
+ **/
+void
+g_file_query_filesystem_info_async (GFile *file,
+ const char *attributes,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GFileIface *iface;
+
+ g_return_if_fail (G_IS_FILE (file));
+
+ iface = G_FILE_GET_IFACE (file);
+ (* iface->query_filesystem_info_async) (file,
+ attributes,
+ io_priority,
+ cancellable,
+ callback,
+ user_data);
+}
+
+/**
+ * g_file_query_filesystem_info_finish:
+ * @file: input #GFile.
+ * @res: a #GAsyncResult.
+ * @error: a #GError.
+ *
+ * Finishes an asynchronous filesystem info query. See
+ * g_file_query_filesystem_info_async().
+ *
+ * Returns: #GFileInfo for given @file or %NULL on error.
+ * Free the returned object with g_object_unref().
+ **/
+GFileInfo *
+g_file_query_filesystem_info_finish (GFile *file,
+ GAsyncResult *res,
+ GError **error)
+{
+ GFileIface *iface;
+
+ g_return_val_if_fail (G_IS_FILE (file), NULL);
+ g_return_val_if_fail (G_IS_ASYNC_RESULT (res), NULL);
+
+ if (G_IS_SIMPLE_ASYNC_RESULT (res))
+ {
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
+ if (g_simple_async_result_propagate_error (simple, error))
+ return NULL;
+ }
+
+ iface = G_FILE_GET_IFACE (file);
+ return (* iface->query_filesystem_info_finish) (file, res, error);
+}
+
+/**
* g_file_find_enclosing_mount:
* @file: input #GFile.
* @cancellable: optional #GCancellable object, %NULL to ignore.
* was cancelled, the error %G_IO_ERROR_CANCELLED will be returned.
*
* Returns: a #GMount where the @file is located or %NULL on error.
+ * Free the returned object with g_object_unref().
**/
GMount *
g_file_find_enclosing_mount (GFile *file,
GFileIface *iface;
g_return_val_if_fail (G_IS_FILE (file), NULL);
-
+
if (g_cancellable_set_error_if_cancelled (cancellable, error))
return NULL;
iface = G_FILE_GET_IFACE (file);
if (iface->find_enclosing_mount == NULL)
{
- g_set_error (error, G_IO_ERROR,
- G_IO_ERROR_NOT_FOUND,
+
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
+ /* Translators: This is an error message when trying to find the
+ * enclosing (user visible) mount of a file, but none exists. */
_("Containing mount does not exist"));
return NULL;
}
-
+
return (* iface->find_enclosing_mount) (file, cancellable, error);
}
+
/**
* g_file_find_enclosing_mount_async:
* @file: a #GFile
* See g_file_find_enclosing_mount_async().
*
* Returns: #GMount for given @file or %NULL on error.
+ * Free the returned object with g_object_unref().
**/
GMount *
g_file_find_enclosing_mount_finish (GFile *file,
* Other errors are possible too, and depend on what kind of filesystem the file is on.
*
* Returns: #GFileInputStream or %NULL on error.
+ * Free the returned object with g_object_unref().
**/
GFileInputStream *
g_file_read (GFile *file,
if (iface->read_fn == NULL)
{
- g_set_error (error, G_IO_ERROR,
- G_IO_ERROR_NOT_SUPPORTED,
- _("Operation not supported"));
+ g_set_error_literal (error, G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ _("Operation not supported"));
return NULL;
}
* was cancelled, the error %G_IO_ERROR_CANCELLED will be returned.
*
* Some file systems don't allow all file names, and may
- * return an G_IO_ERROR_INVALID_FILENAME error.
- * If the file is a directory the G_IO_ERROR_IS_DIRECTORY error will be
+ * return an %G_IO_ERROR_INVALID_FILENAME error.
+ * If the file is a directory the %G_IO_ERROR_IS_DIRECTORY error will be
* returned. Other errors are possible too, and depend on what kind of
* filesystem the file is on.
*
- * Returns: a #GFileOutputStream.
+ * Returns: a #GFileOutputStream, or %NULL on error.
+ * Free the returned object with g_object_unref().
**/
GFileOutputStream *
g_file_append_to (GFile *file,
if (iface->append_to == NULL)
{
- g_set_error (error, G_IO_ERROR,
- G_IO_ERROR_NOT_SUPPORTED,
- _("Operation not supported"));
+ g_set_error_literal (error, G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ _("Operation not supported"));
return NULL;
}
* @error: a #GError, or %NULL
*
* Creates a new file and returns an output stream for writing to it.
- * The file must not already exists.
+ * The file must not already exist.
*
* By default files created are generally readable by everyone,
* but if you pass #G_FILE_CREATE_PRIVATE in @flags the file
* triggering the cancellable object from another thread. If the operation
* was cancelled, the error %G_IO_ERROR_CANCELLED will be returned.
*
- * If a file with this name already exists the G_IO_ERROR_EXISTS error
- * will be returned. If the file is a directory the G_IO_ERROR_IS_DIRECTORY
+ * If a file or directory with this name already exists the G_IO_ERROR_EXISTS
* error will be returned.
* Some file systems don't allow all file names, and may
* return an G_IO_ERROR_INVALID_FILENAME error, and if the name
* filesystem the file is on.
*
* Returns: a #GFileOutputStream for the newly created file, or
- * %NULL on error.
+ * %NULL on error.
+ * Free the returned object with g_object_unref().
**/
GFileOutputStream *
g_file_create (GFile *file,
if (iface->create == NULL)
{
- g_set_error (error, G_IO_ERROR,
- G_IO_ERROR_NOT_SUPPORTED,
- _("Operation not supported"));
+ g_set_error_literal (error, G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ _("Operation not supported"));
return NULL;
}
* @error: a #GError, or %NULL
*
* Returns an output stream for overwriting the file, possibly
- * creating a backup copy of the file first.
+ * creating a backup copy of the file first. If the file doesn't exist,
+ * it will be created.
*
* This will try to replace the file in the safest way possible so
* that any errors during the writing will not affect an already
* filesystem the file is on.
*
* Returns: a #GFileOutputStream or %NULL on error.
+ * Free the returned object with g_object_unref().
**/
GFileOutputStream *
g_file_replace (GFile *file,
if (iface->replace == NULL)
{
- g_set_error (error, G_IO_ERROR,
- G_IO_ERROR_NOT_SUPPORTED,
- _("Operation not supported"));
+ g_set_error_literal (error, G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ _("Operation not supported"));
return NULL;
}
}
/**
+ * g_file_open_readwrite:
+ * @file: #GFile to open
+ * @cancellable: a #GCancellable
+ * @error: a #GError, or %NULL
+ *
+ * Opens an existing file for reading and writing. The result is
+ * a #GFileIOStream that can be used to read and write the contents of the file.
+ *
+ * If @cancellable is not %NULL, then the operation can be cancelled by
+ * triggering the cancellable object from another thread. If the operation
+ * was cancelled, the error %G_IO_ERROR_CANCELLED will be returned.
+ *
+ * If the file does not exist, the G_IO_ERROR_NOT_FOUND error will be returned.
+ * If the file is a directory, the G_IO_ERROR_IS_DIRECTORY error will be returned.
+ * Other errors are possible too, and depend on what kind of filesystem the file is on.
+ * Note that in many non-local file cases read and write streams are not supported,
+ * so make sure you really need to do read and write streaming, rather than
+ * just opening for reading or writing.
+ *
+ * Returns: #GFileIOStream or %NULL on error.
+ * Free the returned object with g_object_unref().
+ *
+ * Since: 2.22
+ **/
+GFileIOStream *
+g_file_open_readwrite (GFile *file,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GFileIface *iface;
+
+ g_return_val_if_fail (G_IS_FILE (file), NULL);
+
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ return NULL;
+
+ iface = G_FILE_GET_IFACE (file);
+
+ if (iface->open_readwrite == NULL)
+ {
+ g_set_error_literal (error, G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ _("Operation not supported"));
+ return NULL;
+ }
+
+ return (* iface->open_readwrite) (file, cancellable, error);
+}
+
+/**
+ * g_file_create_readwrite:
+ * @file: a #GFile
+ * @flags: a set of #GFileCreateFlags
+ * @cancellable: optional #GCancellable object, %NULL to ignore
+ * @error: return location for a #GError, or %NULL
+ *
+ * Creates a new file and returns a stream for reading and writing to it.
+ * The file must not already exist.
+ *
+ * By default files created are generally readable by everyone,
+ * but if you pass #G_FILE_CREATE_PRIVATE in @flags the file
+ * will be made readable only to the current user, to the level that
+ * is supported on the target filesystem.
+ *
+ * If @cancellable is not %NULL, then the operation can be cancelled by
+ * triggering the cancellable object from another thread. If the operation
+ * was cancelled, the error %G_IO_ERROR_CANCELLED will be returned.
+ *
+ * If a file or directory with this name already exists the %G_IO_ERROR_EXISTS
+ * error will be returned. Some file systems don't allow all file names,
+ * and may return an %G_IO_ERROR_INVALID_FILENAME error, and if the name
+ * is too long, %G_IO_ERROR_FILENAME_TOO_LONG will be returned. Other errors
+ * are possible too, and depend on what kind of filesystem the file is on.
+ *
+ * Note that in many non-local file cases read and write streams are not
+ * supported, so make sure you really need to do read and write streaming,
+ * rather than just opening for reading or writing.
+ *
+ * Returns: a #GFileIOStream for the newly created file, or %NULL on error.
+ * Free the returned object with g_object_unref().
+ *
+ * Since: 2.22
+ */
+GFileIOStream *
+g_file_create_readwrite (GFile *file,
+ GFileCreateFlags flags,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GFileIface *iface;
+
+ g_return_val_if_fail (G_IS_FILE (file), NULL);
+
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ return NULL;
+
+ iface = G_FILE_GET_IFACE (file);
+
+ if (iface->create_readwrite == NULL)
+ {
+ g_set_error_literal (error, G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ _("Operation not supported"));
+ return NULL;
+ }
+
+ return (* iface->create_readwrite) (file, flags, cancellable, error);
+}
+
+/**
+ * g_file_replace_readwrite:
+ * @file: a #GFile
+ * @etag: an optional <link linkend="gfile-etag">entity tag</link> for the
+ * current #GFile, or #NULL to ignore
+ * @make_backup: %TRUE if a backup should be created
+ * @flags: a set of #GFileCreateFlags
+ * @cancellable: optional #GCancellable object, %NULL to ignore
+ * @error: return location for a #GError, or %NULL
+ *
+ * Returns an output stream for overwriting the file in readwrite mode,
+ * possibly creating a backup copy of the file first. If the file doesn't
+ * exist, it will be created.
+ *
+ * For details about the behaviour, see g_file_replace() which does the same
+ * thing but returns an output stream only.
+ *
+ * Note that in many non-local file cases read and write streams are not
+ * supported, so make sure you really need to do read and write streaming,
+ * rather than just opening for reading or writing.
+ *
+ * Returns: a #GFileIOStream or %NULL on error.
+ * Free the returned object with g_object_unref().
+ *
+ * Since: 2.22
+ */
+GFileIOStream *
+g_file_replace_readwrite (GFile *file,
+ const char *etag,
+ gboolean make_backup,
+ GFileCreateFlags flags,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GFileIface *iface;
+
+ g_return_val_if_fail (G_IS_FILE (file), NULL);
+
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ return NULL;
+
+ iface = G_FILE_GET_IFACE (file);
+
+ if (iface->replace_readwrite == NULL)
+ {
+ g_set_error_literal (error, G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ _("Operation not supported"));
+ return NULL;
+ }
+
+ return (* iface->replace_readwrite) (file, etag, make_backup, flags, cancellable, error);
+}
+
+/**
* g_file_read_async:
- * @file: input #GFile.
- * @io_priority: the <link linkend="io-priority">I/O priority</link>
- * of the request.
+ * @file: input #GFile
+ * @io_priority: the <link linkend="io-priority">I/O priority</link>
+ * of the request.
* @cancellable: 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
* g_file_read_async().
*
* Returns: a #GFileInputStream or %NULL on error.
+ * Free the returned object with g_object_unref().
**/
GFileInputStream *
g_file_read_finish (GFile *file,
* g_file_append_to_async().
*
* Returns: a valid #GFileOutputStream or %NULL on error.
+ * Free the returned object with g_object_unref().
**/
GFileOutputStream *
g_file_append_to_finish (GFile *file,
* @user_data: the data to pass to callback function
*
* Asynchronously creates a new file and returns an output stream for writing to it.
- * The file must not already exists.
+ * The file must not already exist.
*
* For more details, see g_file_create() which is
* the synchronous version of this call.
* g_file_create_async().
*
* Returns: a #GFileOutputStream or %NULL on error.
+ * Free the returned object with g_object_unref().
**/
GFileOutputStream *
g_file_create_finish (GFile *file,
* g_file_replace_async().
*
* Returns: a #GFileOutputStream, or %NULL on error.
+ * Free the returned object with g_object_unref().
**/
GFileOutputStream *
g_file_replace_finish (GFile *file,
if (g_simple_async_result_propagate_error (simple, error))
return NULL;
}
-
+
iface = G_FILE_GET_IFACE (file);
return (* iface->replace_finish) (file, res, error);
}
-static gboolean
-copy_symlink (GFile *destination,
- GFileCopyFlags flags,
- GCancellable *cancellable,
- const char *target,
- GError **error)
-{
- GError *my_error;
- gboolean tried_delete;
- GFileInfo *info;
- GFileType file_type;
-
- tried_delete = FALSE;
-
- retry:
- my_error = NULL;
- if (!g_file_make_symbolic_link (destination, target, cancellable, &my_error))
- {
- /* Maybe it already existed, and we want to overwrite? */
- if (!tried_delete && (flags & G_FILE_COPY_OVERWRITE) &&
- my_error->domain == G_IO_ERROR && my_error->code == G_IO_ERROR_EXISTS)
- {
- g_error_free (my_error);
+
+/**
+ * g_file_open_readwrite_async:
+ * @file: input #GFile.
+ * @io_priority: the <link linkend="io-priority">I/O priority</link>
+ * of the request.
+ * @cancellable: 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 opens @file for reading and writing.
+ *
+ * For more details, see g_file_open_readwrite() which is
+ * the synchronous version of this call.
+ *
+ * When the operation is finished, @callback will be called. You can then call
+ * g_file_open_readwrite_finish() to get the result of the operation.
+ *
+ * Since: 2.22
+ **/
+void
+g_file_open_readwrite_async (GFile *file,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GFileIface *iface;
+
+ g_return_if_fail (G_IS_FILE (file));
+
+ iface = G_FILE_GET_IFACE (file);
+ (* iface->open_readwrite_async) (file,
+ io_priority,
+ cancellable,
+ callback,
+ user_data);
+}
+
+/**
+ * g_file_open_readwrite_finish:
+ * @file: input #GFile.
+ * @res: a #GAsyncResult.
+ * @error: a #GError, or %NULL
+ *
+ * Finishes an asynchronous file read operation started with
+ * g_file_open_readwrite_async().
+ *
+ * Returns: a #GFileIOStream or %NULL on error.
+ * Free the returned object with g_object_unref().
+ *
+ * Since: 2.22
+ **/
+GFileIOStream *
+g_file_open_readwrite_finish (GFile *file,
+ GAsyncResult *res,
+ GError **error)
+{
+ GFileIface *iface;
+
+ g_return_val_if_fail (G_IS_FILE (file), NULL);
+ g_return_val_if_fail (G_IS_ASYNC_RESULT (res), NULL);
+
+ if (G_IS_SIMPLE_ASYNC_RESULT (res))
+ {
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
+ if (g_simple_async_result_propagate_error (simple, error))
+ return NULL;
+ }
+
+ iface = G_FILE_GET_IFACE (file);
+ return (* iface->open_readwrite_finish) (file, res, error);
+}
+
+
+/**
+ * g_file_create_readwrite_async:
+ * @file: input #GFile
+ * @flags: a set of #GFileCreateFlags
+ * @io_priority: the <link linkend="io-priority">I/O priority</link>
+ * of the request
+ * @cancellable: 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 new file and returns a stream for reading and
+ * writing to it. The file must not already exist.
+ *
+ * For more details, see g_file_create_readwrite() which is
+ * the synchronous version of this call.
+ *
+ * When the operation is finished, @callback will be called. You can then
+ * call g_file_create_readwrite_finish() to get the result of the operation.
+ *
+ * Since: 2.22
+ */
+void
+g_file_create_readwrite_async (GFile *file,
+ GFileCreateFlags flags,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GFileIface *iface;
+
+ g_return_if_fail (G_IS_FILE (file));
+
+ iface = G_FILE_GET_IFACE (file);
+ (* iface->create_readwrite_async) (file,
+ flags,
+ io_priority,
+ cancellable,
+ callback,
+ user_data);
+}
+
+/**
+ * g_file_create_readwrite_finish:
+ * @file: input #GFile
+ * @res: a #GAsyncResult
+ * @error: a #GError, or %NULL
+ *
+ * Finishes an asynchronous file create operation started with
+ * g_file_create_readwrite_async().
+ *
+ * Returns: a #GFileIOStream or %NULL on error.
+ * Free the returned object with g_object_unref().
+ *
+ * Since: 2.22
+ **/
+GFileIOStream *
+g_file_create_readwrite_finish (GFile *file,
+ GAsyncResult *res,
+ GError **error)
+{
+ GFileIface *iface;
+
+ g_return_val_if_fail (G_IS_FILE (file), NULL);
+ g_return_val_if_fail (G_IS_ASYNC_RESULT (res), NULL);
+
+ if (G_IS_SIMPLE_ASYNC_RESULT (res))
+ {
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
+ if (g_simple_async_result_propagate_error (simple, error))
+ return NULL;
+ }
+
+ iface = G_FILE_GET_IFACE (file);
+ return (* iface->create_readwrite_finish) (file, res, error);
+}
+
+/**
+ * g_file_replace_readwrite_async:
+ * @file: input #GFile.
+ * @etag: an <link linkend="gfile-etag">entity tag</link> for the
+ * current #GFile, or NULL to ignore.
+ * @make_backup: %TRUE if a backup should be created.
+ * @flags: a set of #GFileCreateFlags.
+ * @io_priority: the <link linkend="io-priority">I/O priority</link>
+ * of the request.
+ * @cancellable: 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 overwrites the file in read-write mode, replacing the
+ * contents, possibly creating a backup copy of the file first.
+ *
+ * For more details, see g_file_replace_readwrite() which is
+ * the synchronous version of this call.
+ *
+ * When the operation is finished, @callback will be called. You can then
+ * call g_file_replace_readwrite_finish() to get the result of the operation.
+ *
+ * Since: 2.22
+ */
+void
+g_file_replace_readwrite_async (GFile *file,
+ const char *etag,
+ gboolean make_backup,
+ GFileCreateFlags flags,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GFileIface *iface;
+
+ g_return_if_fail (G_IS_FILE (file));
+
+ iface = G_FILE_GET_IFACE (file);
+ (* iface->replace_readwrite_async) (file,
+ etag,
+ make_backup,
+ flags,
+ io_priority,
+ cancellable,
+ callback,
+ user_data);
+}
+
+/**
+ * g_file_replace_readwrite_finish:
+ * @file: input #GFile.
+ * @res: a #GAsyncResult.
+ * @error: a #GError, or %NULL
+ *
+ * Finishes an asynchronous file replace operation started with
+ * g_file_replace_readwrite_async().
+ *
+ * Returns: a #GFileIOStream, or %NULL on error.
+ * Free the returned object with g_object_unref().
+ *
+ * Since: 2.22
+ */
+GFileIOStream *
+g_file_replace_readwrite_finish (GFile *file,
+ GAsyncResult *res,
+ GError **error)
+{
+ GFileIface *iface;
+
+ g_return_val_if_fail (G_IS_FILE (file), NULL);
+ g_return_val_if_fail (G_IS_ASYNC_RESULT (res), NULL);
+
+ if (G_IS_SIMPLE_ASYNC_RESULT (res))
+ {
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
+ if (g_simple_async_result_propagate_error (simple, error))
+ return NULL;
+ }
+
+ iface = G_FILE_GET_IFACE (file);
+ return (* iface->replace_readwrite_finish) (file, res, error);
+}
+
+static gboolean
+copy_symlink (GFile *destination,
+ GFileCopyFlags flags,
+ GCancellable *cancellable,
+ const char *target,
+ GError **error)
+{
+ GError *my_error;
+ gboolean tried_delete;
+ GFileInfo *info;
+ GFileType file_type;
+
+ tried_delete = FALSE;
+
+ retry:
+ my_error = NULL;
+ if (!g_file_make_symbolic_link (destination, target, cancellable, &my_error))
+ {
+ /* Maybe it already existed, and we want to overwrite? */
+ if (!tried_delete && (flags & G_FILE_COPY_OVERWRITE) &&
+ my_error->domain == G_IO_ERROR && my_error->code == G_IO_ERROR_EXISTS)
+ {
+ g_error_free (my_error);
/* Don't overwrite if the destination is a directory */
if (file_type == G_FILE_TYPE_DIRECTORY)
{
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY,
- _("Can't copy over directory"));
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY,
+ _("Can't copy over directory"));
return FALSE;
}
}
{
if (file_type == G_FILE_TYPE_DIRECTORY)
{
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_WOULD_MERGE,
- _("Can't copy directory over directory"));
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_WOULD_MERGE,
+ _("Can't copy directory over directory"));
return NULL;
}
/* continue to would_recurse error */
}
else
{
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_EXISTS,
- _("Target file exists"));
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_EXISTS,
+ _("Target file exists"));
return NULL;
}
}
g_error_free (my_error);
}
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_WOULD_RECURSE,
- _("Can't recursively copy directory"));
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_WOULD_RECURSE,
+ _("Can't recursively copy directory"));
return NULL;
}
static gboolean
should_copy (GFileAttributeInfo *info,
- gboolean as_move)
+ gboolean as_move,
+ gboolean skip_perms)
{
+ if (skip_perms && strcmp(info->name, "unix::mode") == 0)
+ return FALSE;
+
if (as_move)
return info->flags & G_FILE_ATTRIBUTE_INFO_COPY_WHEN_MOVED;
return info->flags & G_FILE_ATTRIBUTE_INFO_COPY_WITH_FILE;
static char *
build_attribute_list_for_copy (GFileAttributeInfoList *attributes,
GFileAttributeInfoList *namespaces,
- gboolean as_move)
+ gboolean as_move,
+ gboolean skip_perms)
{
GString *s;
gboolean first;
{
for (i = 0; i < attributes->n_infos; i++)
{
- if (should_copy (&attributes->infos[i], as_move))
+ if (should_copy (&attributes->infos[i], as_move, skip_perms))
{
if (first)
first = FALSE;
{
for (i = 0; i < namespaces->n_infos; i++)
{
- if (should_copy (&namespaces->infos[i], as_move))
+ if (should_copy (&namespaces->infos[i], as_move, FALSE))
{
if (first)
first = FALSE;
g_string_append_c (s, ',');
g_string_append (s, namespaces->infos[i].name);
- g_string_append (s, ":*");
+ g_string_append (s, "::*");
}
}
}
*
* Normally only a subset of the file attributes are copied,
* those that are copies in a normal file copy operation
- * (which for instance does not include e.g. mtime). However
+ * (which for instance does not include e.g. owner). However
* if #G_FILE_COPY_ALL_METADATA is specified in @flags, then
- * all the metadata that is possible to copy is copied.
+ * all the metadata that is possible to copy is copied. This
+ * is useful when implementing move by copy + delete source.
*
* Returns: %TRUE if the attributes were copied successfully, %FALSE otherwise.
**/
GFileInfo *info;
gboolean as_move;
gboolean source_nofollow_symlinks;
+ gboolean skip_perms;
as_move = flags & G_FILE_COPY_ALL_METADATA;
source_nofollow_symlinks = flags & G_FILE_COPY_NOFOLLOW_SYMLINKS;
+ skip_perms = (flags & G_FILE_COPY_TARGET_DEFAULT_PERMS) != 0;
/* Ignore errors here, if the target supports no attributes there is nothing to copy */
attributes = g_file_query_settable_attributes (destination, cancellable, NULL);
if (attributes == NULL && namespaces == NULL)
return TRUE;
- attrs_to_read = build_attribute_list_for_copy (attributes, namespaces, as_move);
+ attrs_to_read = build_attribute_list_for_copy (attributes, namespaces, as_move, skip_perms);
/* Ignore errors here, if we can't read some info (e.g. if it doesn't exist)
* we just don't copy it.
if (info)
{
res = g_file_set_attributes_from_info (destination,
- info, 0,
+ info,
+ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
cancellable,
error);
g_object_unref (info);
return res;
}
-/* Closes the streams */
static gboolean
copy_stream_with_progress (GInputStream *in,
GOutputStream *out,
+ GFile *source,
GCancellable *cancellable,
GFileProgressCallback progress_callback,
gpointer progress_callback_data,
{
gssize n_read, n_written;
goffset current_size;
- char buffer[8192], *p;
+ char buffer[1024*64], *p;
gboolean res;
goffset total_size;
GFileInfo *info;
- total_size = 0;
- info = g_file_input_stream_query_info (G_FILE_INPUT_STREAM (in),
- G_FILE_ATTRIBUTE_STANDARD_SIZE,
- cancellable, NULL);
- if (info)
+ total_size = -1;
+ /* avoid performance impact of querying total size when it's not needed */
+ if (progress_callback)
{
- total_size = g_file_info_get_size (info);
- g_object_unref (info);
+ info = g_file_input_stream_query_info (G_FILE_INPUT_STREAM (in),
+ G_FILE_ATTRIBUTE_STANDARD_SIZE,
+ cancellable, NULL);
+ if (info)
+ {
+ if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_SIZE))
+ total_size = g_file_info_get_size (info);
+ g_object_unref (info);
+ }
+
+ if (total_size == -1)
+ {
+ info = g_file_query_info (source,
+ G_FILE_ATTRIBUTE_STANDARD_SIZE,
+ G_FILE_QUERY_INFO_NONE,
+ cancellable, NULL);
+ if (info)
+ {
+ if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_SIZE))
+ total_size = g_file_info_get_size (info);
+ g_object_unref (info);
+ }
+ }
}
+
+ if (total_size == -1)
+ total_size = 0;
current_size = 0;
res = TRUE;
if (!res)
break;
-
+
if (progress_callback)
progress_callback (current_size, total_size, progress_callback_data);
}
- if (!res)
- error = NULL; /* Ignore further errors */
-
/* Make sure we send full copied size */
if (progress_callback)
progress_callback (current_size, total_size, progress_callback_data);
-
- /* Don't care about errors in source here */
- g_input_stream_close (in, cancellable, NULL);
+ return res;
+}
- /* But write errors on close are bad! */
- if (!g_output_stream_close (out, cancellable, error))
- res = FALSE;
+#ifdef HAVE_SPLICE
+
+static gboolean
+do_splice (int fd_in,
+ loff_t *off_in,
+ int fd_out,
+ loff_t *off_out,
+ size_t len,
+ long *bytes_transferd,
+ GError **error)
+{
+ long result;
+
+retry:
+ result = splice (fd_in, off_in, fd_out, off_out, len, SPLICE_F_MORE);
+
+ if (result == -1)
+ {
+ int errsv = errno;
+
+ if (errsv == EINTR)
+ goto retry;
+ else if (errsv == ENOSYS || errsv == EINVAL)
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+ _("Splice not supported"));
+ else
+ g_set_error (error, G_IO_ERROR,
+ g_io_error_from_errno (errsv),
+ _("Error splicing file: %s"),
+ g_strerror (errsv));
+
+ return FALSE;
+ }
+
+ *bytes_transferd = result;
+ return TRUE;
+}
+
+static gboolean
+splice_stream_with_progress (GInputStream *in,
+ GOutputStream *out,
+ GCancellable *cancellable,
+ GFileProgressCallback progress_callback,
+ gpointer progress_callback_data,
+ GError **error)
+{
+ int buffer[2];
+ gboolean res;
+ goffset total_size;
+ loff_t offset_in;
+ loff_t offset_out;
+ int fd_in, fd_out;
+
+ fd_in = g_file_descriptor_based_get_fd (G_FILE_DESCRIPTOR_BASED (in));
+ fd_out = g_file_descriptor_based_get_fd (G_FILE_DESCRIPTOR_BASED (out));
+
+ if (pipe (buffer) != 0)
+ {
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+ "Pipe creation failed");
+ return FALSE;
+ }
+
+ total_size = -1;
+ /* avoid performance impact of querying total size when it's not needed */
+ if (progress_callback)
+ {
+ struct stat sbuf;
+
+ if (fstat (fd_in, &sbuf) == 0)
+ total_size = sbuf.st_size;
+ }
+
+ if (total_size == -1)
+ total_size = 0;
+
+ offset_in = offset_out = 0;
+ res = FALSE;
+ while (TRUE)
+ {
+ long n_read;
+ long n_written;
+
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ break;
+
+ if (!do_splice (fd_in, &offset_in, buffer[1], NULL, 1024*64, &n_read, error))
+ break;
+
+ if (n_read == 0)
+ {
+ res = TRUE;
+ break;
+ }
+
+ while (n_read > 0)
+ {
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ goto out;
+
+ if (!do_splice (buffer[0], NULL, fd_out, &offset_out, n_read, &n_written, error))
+ goto out;
+
+ n_read -= n_written;
+ }
+
+ if (progress_callback)
+ progress_callback (offset_in, total_size, progress_callback_data);
+ }
+
+ /* Make sure we send full copied size */
+ if (progress_callback)
+ progress_callback (offset_in, total_size, progress_callback_data);
+
+ out:
+ close (buffer[0]);
+ close (buffer[1]);
- g_object_unref (in);
- g_object_unref (out);
-
return res;
}
+#endif
static gboolean
file_copy_fallback (GFile *source,
GOutputStream *out;
GFileInfo *info;
const char *target;
+ gboolean result;
+#ifdef HAVE_SPLICE
+ gboolean fallback = TRUE;
+#endif
+
+ /* need to know the file type */
+ info = g_file_query_info (source,
+ G_FILE_ATTRIBUTE_STANDARD_TYPE "," G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET,
+ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+ cancellable,
+ error);
+
+ if (info == NULL)
+ return FALSE;
/* Maybe copy the symlink? */
- if (flags & G_FILE_COPY_NOFOLLOW_SYMLINKS)
+ if ((flags & G_FILE_COPY_NOFOLLOW_SYMLINKS) &&
+ g_file_info_get_file_type (info) == G_FILE_TYPE_SYMBOLIC_LINK)
{
- info = g_file_query_info (source,
- G_FILE_ATTRIBUTE_STANDARD_TYPE "," G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET,
- G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
- cancellable,
- error);
- if (info == NULL)
- return FALSE;
-
- if (g_file_info_get_file_type (info) == G_FILE_TYPE_SYMBOLIC_LINK &&
- (target = g_file_info_get_symlink_target (info)) != NULL)
+ target = g_file_info_get_symlink_target (info);
+ if (target)
{
if (!copy_symlink (destination, flags, cancellable, target, error))
{
g_object_unref (info);
goto copied_file;
}
-
+ /* ... else fall back on a regular file copy */
+ g_object_unref (info);
+ }
+ /* Handle "special" files (pipes, device nodes, ...)? */
+ else if (g_file_info_get_file_type (info) == G_FILE_TYPE_SPECIAL)
+ {
+ /* FIXME: could try to recreate device nodes and others? */
+
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+ _("Can't copy special file"));
g_object_unref (info);
+ return FALSE;
}
-
+ /* Everything else should just fall back on a regular copy. */
+ else
+ g_object_unref (info);
+
in = open_source_for_copy (source, destination, flags, cancellable, error);
if (in == NULL)
return FALSE;
if (flags & G_FILE_COPY_OVERWRITE)
{
out = (GOutputStream *)g_file_replace (destination,
- NULL, 0,
+ NULL,
flags & G_FILE_COPY_BACKUP,
+ G_FILE_CREATE_REPLACE_DESTINATION,
cancellable, error);
}
else
return FALSE;
}
- if (!copy_stream_with_progress (in, out, cancellable,
- progress_callback, progress_callback_data,
- error))
+#ifdef HAVE_SPLICE
+ if (G_IS_FILE_DESCRIPTOR_BASED (in) && G_IS_FILE_DESCRIPTOR_BASED (out))
+ {
+ GError *splice_err = NULL;
+
+ result = splice_stream_with_progress (in, out, cancellable,
+ progress_callback, progress_callback_data,
+ &splice_err);
+
+ if (result || !g_error_matches (splice_err, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED))
+ {
+ fallback = FALSE;
+ if (!result)
+ g_propagate_error (error, splice_err);
+ }
+ else
+ g_clear_error (&splice_err);
+ }
+
+ if (fallback)
+#endif
+ result = copy_stream_with_progress (in, out, source, cancellable,
+ progress_callback, progress_callback_data,
+ error);
+
+ /* Don't care about errors in source here */
+ g_input_stream_close (in, cancellable, NULL);
+
+ /* But write errors on close are bad! */
+ if (!g_output_stream_close (out, cancellable, result ? error : NULL))
+ result = FALSE;
+
+ g_object_unref (in);
+ g_object_unref (out);
+
+ if (result == FALSE)
return FALSE;
copied_file:
-
/* Ignore errors here. Failure to copy metadata is not a hard error */
g_file_copy_attributes (source, destination,
flags, cancellable, NULL);
g_propagate_error (error, my_error);
return FALSE;
}
+ else
+ g_clear_error (&my_error);
}
/* If the types are different, and the destination method failed
g_propagate_error (error, my_error);
return FALSE;
}
+ else
+ g_clear_error (&my_error);
}
}
if (flags & G_FILE_COPY_NO_FALLBACK_FOR_MOVE)
{
- g_set_error (error, G_IO_ERROR,
- G_IO_ERROR_NOT_SUPPORTED,
- _("Operation not supported"));
+ g_set_error_literal (error, G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ _("Operation not supported"));
return FALSE;
}
* @cancellable: optional #GCancellable object, %NULL to ignore.
* @error: a #GError, or %NULL
*
- * Creates a directory.
+ * Creates a directory. Note that this will only create a child directory of
+ * the immediate parent directory of the path or URI given by the #GFile. To
+ * recursively create directories, see g_file_make_directory_with_parents().
+ * This function will fail if the parent directory does not exist, setting
+ * @error to %G_IO_ERROR_NOT_FOUND. If the file system doesn't support creating
+ * directories, this function will fail, setting @error to
+ * %G_IO_ERROR_NOT_SUPPORTED.
+ *
+ * For a local #GFile the newly created directory will have the default
+ * (current) ownership and permissions of the current process.
*
* If @cancellable is not %NULL, then the operation can be cancelled by
* triggering the cancellable object from another thread. If the operation
if (iface->make_directory == NULL)
{
- g_set_error (error, G_IO_ERROR,
- G_IO_ERROR_NOT_SUPPORTED,
- _("Operation not supported"));
+ g_set_error_literal (error, G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ _("Operation not supported"));
return FALSE;
}
}
/**
- * g_file_make_symbolic_link:
+ * g_file_make_directory_with_parents:
* @file: input #GFile.
- * @symlink_value: a string with the value of the new symlink.
* @cancellable: optional #GCancellable object, %NULL to ignore.
- * @error: a #GError.
- *
- * Creates a symbolic link.
+ * @error: a #GError, or %NULL
*
+ * Creates a directory and any parent directories that may not exist similar to
+ * 'mkdir -p'. If the file system does not support creating directories, this
+ * function will fail, setting @error to %G_IO_ERROR_NOT_SUPPORTED.
+ *
+ * For a local #GFile the newly created directories will have the default
+ * (current) ownership and permissions of the current process.
+ *
* If @cancellable is not %NULL, then the operation can be cancelled by
* triggering the cancellable object from another thread. If the operation
* was cancelled, the error %G_IO_ERROR_CANCELLED will be returned.
*
- * Returns: %TRUE on the creation of a new symlink, %FALSE otherwise.
+ * Returns: %TRUE if all directories have been successfully created, %FALSE
+ * otherwise.
+ *
+ * Since: 2.18
**/
gboolean
+g_file_make_directory_with_parents (GFile *file,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean result;
+ GFile *parent_file, *work_file;
+ GList *list = NULL, *l;
+ GError *my_error = NULL;
+
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ return FALSE;
+
+ result = g_file_make_directory (file, cancellable, &my_error);
+ if (result || my_error->code != G_IO_ERROR_NOT_FOUND)
+ {
+ if (my_error)
+ g_propagate_error (error, my_error);
+ return result;
+ }
+
+ work_file = file;
+
+ while (!result && my_error->code == G_IO_ERROR_NOT_FOUND)
+ {
+ g_clear_error (&my_error);
+
+ parent_file = g_file_get_parent (work_file);
+ if (parent_file == NULL)
+ break;
+ result = g_file_make_directory (parent_file, cancellable, &my_error);
+
+ if (!result && my_error->code == G_IO_ERROR_NOT_FOUND)
+ list = g_list_prepend (list, parent_file);
+
+ work_file = parent_file;
+ }
+
+ for (l = list; result && l; l = l->next)
+ {
+ result = g_file_make_directory ((GFile *) l->data, cancellable, &my_error);
+ }
+
+ /* Clean up */
+ while (list != NULL)
+ {
+ g_object_unref ((GFile *) list->data);
+ list = g_list_remove (list, list->data);
+ }
+
+ if (!result)
+ {
+ g_propagate_error (error, my_error);
+ return result;
+ }
+
+ return g_file_make_directory (file, cancellable, error);
+}
+
+/**
+ * g_file_make_symbolic_link:
+ * @file: a #GFile with the name of the symlink to create
+ * @symlink_value: a string with the path for the target of the new symlink
+ * @cancellable: optional #GCancellable object, %NULL to ignore.
+ * @error: a #GError.
+ *
+ * Creates a symbolic link named @file which contains the string
+ * @symlink_value.
+ *
+ * If @cancellable is not %NULL, then the operation can be cancelled by
+ * triggering the cancellable object from another thread. If the operation
+ * was cancelled, the error %G_IO_ERROR_CANCELLED will be returned.
+ *
+ * Returns: %TRUE on the creation of a new symlink, %FALSE otherwise.
+ */
+gboolean
g_file_make_symbolic_link (GFile *file,
const char *symlink_value,
GCancellable *cancellable,
if (*symlink_value == '\0')
{
- g_set_error (error, G_IO_ERROR,
- G_IO_ERROR_INVALID_ARGUMENT,
- _("Invalid symlink value given"));
+ g_set_error_literal (error, G_IO_ERROR,
+ G_IO_ERROR_INVALID_ARGUMENT,
+ _("Invalid symlink value given"));
return FALSE;
}
if (iface->make_symbolic_link == NULL)
{
- g_set_error (error, G_IO_ERROR,
- G_IO_ERROR_NOT_SUPPORTED,
- _("Operation not supported"));
+ g_set_error_literal (error, G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ _("Operation not supported"));
return FALSE;
}
* @cancellable: optional #GCancellable object, %NULL to ignore.
* @error: a #GError, or %NULL
*
- * Deletes a file.
+ * Deletes a file. If the @file is a directory, it will only be deleted if it
+ * is empty.
*
* If @cancellable is not %NULL, then the operation can be cancelled by
* triggering the cancellable object from another thread. If the operation
if (iface->delete_file == NULL)
{
- g_set_error (error, G_IO_ERROR,
- G_IO_ERROR_NOT_SUPPORTED,
- _("Operation not supported"));
+ g_set_error_literal (error, G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ _("Operation not supported"));
return FALSE;
}
if (iface->trash == NULL)
{
- g_set_error (error,
- G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
- _("Trash not supported"));
+ g_set_error_literal (error,
+ G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+ _("Trash not supported"));
return FALSE;
}
* triggering the cancellable object from another thread. If the operation
* was cancelled, the error %G_IO_ERROR_CANCELLED will be returned.
*
- * Returns: a #GFile specifying what @file was renamed to, or %NULL if there was an error.
+ * Returns: a #GFile specifying what @file was renamed to, or %NULL
+ * if there was an error.
+ * Free the returned object with g_object_unref().
**/
GFile *
g_file_set_display_name (GFile *file,
*
* Asynchronously sets the display name for a given #GFile.
*
- * For more details, see g_set_display_name() which is
+ * For more details, see g_file_set_display_name() which is
* the synchronous version of this call.
*
* When the operation is finished, @callback will be called. You can then call
* g_file_set_display_name_async().
*
* Returns: a #GFile or %NULL on error.
+ * Free the returned object with g_object_unref().
**/
GFile *
g_file_set_display_name_finish (GFile *file,
if (iface->set_attribute == NULL)
{
- g_set_error (error, G_IO_ERROR,
- G_IO_ERROR_NOT_SUPPORTED,
- _("Operation not supported"));
+ g_set_error_literal (error, G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ _("Operation not supported"));
return FALSE;
}
/**
* g_file_mount_mountable:
* @file: input #GFile.
+ * @flags: flags affecting the operation
* @mount_operation: a #GMountOperation, or %NULL to avoid user interaction.
* @cancellable: optional #GCancellable object, %NULL to ignore.
* @callback: a #GAsyncReadyCallback to call when the request is satisfied, or %NULL.
**/
void
g_file_mount_mountable (GFile *file,
+ GMountMountFlags flags,
GMountOperation *mount_operation,
GCancellable *cancellable,
GAsyncReadyCallback callback,
iface = G_FILE_GET_IFACE (file);
- if (iface->mount_mountable == NULL)
- g_simple_async_report_error_in_idle (G_OBJECT (file),
- callback,
- user_data,
- G_IO_ERROR,
- G_IO_ERROR_NOT_SUPPORTED,
- _("Operation not supported"));
+ if (iface->mount_mountable == NULL)
+ {
+ g_simple_async_report_error_in_idle (G_OBJECT (file),
+ callback,
+ user_data,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ _("Operation not supported"));
+ return;
+ }
(* iface->mount_mountable) (file,
+ flags,
mount_operation,
cancellable,
callback,
* with g_file_mount_mountable().
*
* Returns: a #GFile or %NULL on error.
+ * Free the returned object with g_object_unref().
**/
GFile *
g_file_mount_mountable_finish (GFile *file,
*
* When the operation is finished, @callback will be called. You can then call
* g_file_unmount_mountable_finish() to get the result of the operation.
+ *
+ * Deprecated: 2.22: Use g_file_unmount_mountable_with_operation() instead.
**/
void
g_file_unmount_mountable (GFile *file,
iface = G_FILE_GET_IFACE (file);
if (iface->unmount_mountable == NULL)
- g_simple_async_report_error_in_idle (G_OBJECT (file),
- callback,
- user_data,
- G_IO_ERROR,
- G_IO_ERROR_NOT_SUPPORTED,
- _("Operation not supported"));
+ {
+ g_simple_async_report_error_in_idle (G_OBJECT (file),
+ callback,
+ user_data,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ _("Operation not supported"));
+ return;
+ }
(* iface->unmount_mountable) (file,
flags,
*
* Returns: %TRUE if the operation finished successfully. %FALSE
* otherwise.
+ *
+ * Deprecated: 2.22: Use g_file_unmount_mountable_with_operation_finish() instead.
**/
gboolean
g_file_unmount_mountable_finish (GFile *file,
}
/**
+ * g_file_unmount_mountable_with_operation:
+ * @file: input #GFile.
+ * @flags: flags affecting the operation
+ * @mount_operation: a #GMountOperation, or %NULL to avoid user interaction.
+ * @cancellable: optional #GCancellable object, %NULL to ignore.
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied, or %NULL.
+ * @user_data: the data to pass to callback function
+ *
+ * Unmounts a file of type G_FILE_TYPE_MOUNTABLE.
+ *
+ * If @cancellable is not %NULL, then the operation can be cancelled by
+ * triggering the cancellable object from another thread. If the operation
+ * was cancelled, the error %G_IO_ERROR_CANCELLED will be returned.
+ *
+ * When the operation is finished, @callback will be called. You can then call
+ * g_file_unmount_mountable_finish() to get the result of the operation.
+ *
+ * Since: 2.22
+ **/
+void
+g_file_unmount_mountable_with_operation (GFile *file,
+ GMountUnmountFlags flags,
+ GMountOperation *mount_operation,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GFileIface *iface;
+
+ g_return_if_fail (G_IS_FILE (file));
+
+ iface = G_FILE_GET_IFACE (file);
+
+ if (iface->unmount_mountable == NULL && iface->unmount_mountable_with_operation == NULL)
+ {
+ g_simple_async_report_error_in_idle (G_OBJECT (file),
+ callback,
+ user_data,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ _("Operation not supported"));
+ return;
+ }
+
+ if (iface->unmount_mountable_with_operation != NULL)
+ (* iface->unmount_mountable_with_operation) (file,
+ flags,
+ mount_operation,
+ cancellable,
+ callback,
+ user_data);
+ else
+ (* iface->unmount_mountable) (file,
+ flags,
+ cancellable,
+ callback,
+ user_data);
+}
+
+/**
+ * g_file_unmount_mountable_with_operation_finish:
+ * @file: input #GFile.
+ * @result: a #GAsyncResult.
+ * @error: a #GError, or %NULL
+ *
+ * Finishes an unmount operation, see g_file_unmount_mountable_with_operation() for details.
+ *
+ * Finish an asynchronous unmount operation that was started
+ * with g_file_unmount_mountable_with_operation().
+ *
+ * Returns: %TRUE if the operation finished successfully. %FALSE
+ * otherwise.
+ *
+ * Since: 2.22
+ **/
+gboolean
+g_file_unmount_mountable_with_operation_finish (GFile *file,
+ GAsyncResult *result,
+ GError **error)
+{
+ GFileIface *iface;
+
+ g_return_val_if_fail (G_IS_FILE (file), 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_FILE_GET_IFACE (file);
+ if (iface->unmount_mountable_with_operation_finish != NULL)
+ return (* iface->unmount_mountable_with_operation_finish) (file, result, error);
+ else
+ return (* iface->unmount_mountable_finish) (file, result, error);
+}
+
+/**
* g_file_eject_mountable:
* @file: input #GFile.
* @flags: flags affecting the operation
* If @cancellable is not %NULL, then the operation can be cancelled by
* triggering the cancellable object from another thread. If the operation
* was cancelled, the error %G_IO_ERROR_CANCELLED will be returned.
+ *
+ * Deprecated: 2.22: Use g_file_eject_mountable_with_operation() instead.
**/
void
g_file_eject_mountable (GFile *file,
iface = G_FILE_GET_IFACE (file);
- if (iface->eject_mountable == NULL)
- g_simple_async_report_error_in_idle (G_OBJECT (file),
- callback,
- user_data,
- G_IO_ERROR,
- G_IO_ERROR_NOT_SUPPORTED,
- _("Operation not supported"));
+ if (iface->eject_mountable == NULL)
+ {
+ g_simple_async_report_error_in_idle (G_OBJECT (file),
+ callback,
+ user_data,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ _("Operation not supported"));
+ return;
+ }
(* iface->eject_mountable) (file,
flags,
*
* Returns: %TRUE if the @file was ejected successfully. %FALSE
* otherwise.
+ *
+ * Deprecated: 2.22: Use g_file_eject_mountable_with_operation_finish() instead.
**/
gboolean
g_file_eject_mountable_finish (GFile *file,
}
/**
+ * g_file_eject_mountable_with_operation:
+ * @file: input #GFile.
+ * @flags: flags affecting the operation
+ * @mount_operation: a #GMountOperation, or %NULL to avoid user interaction.
+ * @cancellable: optional #GCancellable object, %NULL to ignore.
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied, or %NULL.
+ * @user_data: the data to pass to callback function
+ *
+ * Starts an asynchronous eject on a mountable.
+ * When this operation has completed, @callback will be called with
+ * @user_user data, and the operation can be finalized with
+ * g_file_eject_mountable_with_operation_finish().
+ *
+ * If @cancellable is not %NULL, then the operation can be cancelled by
+ * triggering the cancellable object from another thread. If the operation
+ * was cancelled, the error %G_IO_ERROR_CANCELLED will be returned.
+ *
+ * Since: 2.22
+ **/
+void
+g_file_eject_mountable_with_operation (GFile *file,
+ GMountUnmountFlags flags,
+ GMountOperation *mount_operation,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GFileIface *iface;
+
+ g_return_if_fail (G_IS_FILE (file));
+
+ iface = G_FILE_GET_IFACE (file);
+
+ if (iface->eject_mountable == NULL && iface->eject_mountable_with_operation == NULL)
+ {
+ g_simple_async_report_error_in_idle (G_OBJECT (file),
+ callback,
+ user_data,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ _("Operation not supported"));
+ return;
+ }
+
+ if (iface->eject_mountable_with_operation != NULL)
+ (* iface->eject_mountable_with_operation) (file,
+ flags,
+ mount_operation,
+ cancellable,
+ callback,
+ user_data);
+ else
+ (* iface->eject_mountable) (file,
+ flags,
+ cancellable,
+ callback,
+ user_data);
+}
+
+/**
+ * g_file_eject_mountable_with_operation_finish:
+ * @file: input #GFile.
+ * @result: a #GAsyncResult.
+ * @error: a #GError, or %NULL
+ *
+ * Finishes an asynchronous eject operation started by
+ * g_file_eject_mountable_with_operation().
+ *
+ * Returns: %TRUE if the @file was ejected successfully. %FALSE
+ * otherwise.
+ *
+ * Since: 2.22
+ **/
+gboolean
+g_file_eject_mountable_with_operation_finish (GFile *file,
+ GAsyncResult *result,
+ GError **error)
+{
+ GFileIface *iface;
+
+ g_return_val_if_fail (G_IS_FILE (file), 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_FILE_GET_IFACE (file);
+ if (iface->eject_mountable_with_operation_finish != NULL)
+ return (* iface->eject_mountable_with_operation_finish) (file, result, error);
+ else
+ return (* iface->eject_mountable_finish) (file, result, error);
+}
+
+/**
* g_file_monitor_directory:
* @file: input #GFile.
* @flags: a set of #GFileMonitorFlags.
* triggering the cancellable object from another thread. If the operation
* was cancelled, the error %G_IO_ERROR_CANCELLED will be returned.
*
- * Returns: a #GFileMonitor for the given @file,
- * or %NULL on error.
+ * Returns: a #GFileMonitor for the given @file, or %NULL on error.
+ * Free the returned object with g_object_unref().
**/
GFileMonitor*
g_file_monitor_directory (GFile *file,
if (iface->monitor_dir == NULL)
{
- g_set_error (error, G_IO_ERROR,
- G_IO_ERROR_NOT_SUPPORTED,
- _("Operation not supported"));
+ g_set_error_literal (error, G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ _("Operation not supported"));
return NULL;
}
* triggering the cancellable object from another thread. If the operation
* was cancelled, the error %G_IO_ERROR_CANCELLED will be returned.
*
- * Returns: a #GFileMonitor for the given @file.
+ * Returns: a #GFileMonitor for the given @file, or %NULL on error.
+ * Free the returned object with g_object_unref().
**/
GFileMonitor*
g_file_monitor_file (GFile *file,
if (monitor == NULL)
monitor = _g_poll_file_monitor_new (file);
- return monitor;
+ return monitor;
+}
+
+/**
+ * g_file_monitor:
+ * @file: input #GFile
+ * @flags: a set of #GFileMonitorFlags
+ * @cancellable: optional #GCancellable object, %NULL to ignore
+ * @error: a #GError, or %NULL
+ *
+ * Obtains a file or directory monitor for the given file, depending
+ * on the type of the file.
+ *
+ * If @cancellable is not %NULL, then the operation can be cancelled by
+ * triggering the cancellable object from another thread. If the operation
+ * was cancelled, the error %G_IO_ERROR_CANCELLED will be returned.
+ *
+ * Returns: a #GFileMonitor for the given @file, or %NULL on error.
+ * Free the returned object with g_object_unref().
+ *
+ * Since: 2.18
+ */
+GFileMonitor*
+g_file_monitor (GFile *file,
+ GFileMonitorFlags flags,
+ GCancellable *cancellable,
+ GError **error)
+{
+ if (g_file_query_file_type (file, 0, cancellable) == G_FILE_TYPE_DIRECTORY)
+ return g_file_monitor_directory (file, flags, cancellable, error);
+ else
+ return g_file_monitor_file (file, flags, cancellable, error);
}
/********************************************
typedef struct {
char *attributes;
+ GFileInfo *info;
+} QueryFilesystemInfoAsyncData;
+
+static void
+query_filesystem_info_data_free (QueryFilesystemInfoAsyncData *data)
+{
+ if (data->info)
+ g_object_unref (data->info);
+ g_free (data->attributes);
+ g_free (data);
+}
+
+static void
+query_filesystem_info_async_thread (GSimpleAsyncResult *res,
+ GObject *object,
+ GCancellable *cancellable)
+{
+ GError *error = NULL;
+ QueryFilesystemInfoAsyncData *data;
+ GFileInfo *info;
+
+ data = g_simple_async_result_get_op_res_gpointer (res);
+
+ info = g_file_query_filesystem_info (G_FILE (object), data->attributes, cancellable, &error);
+
+ if (info == NULL)
+ {
+ g_simple_async_result_set_from_error (res, error);
+ g_error_free (error);
+ }
+ else
+ data->info = info;
+}
+
+static void
+g_file_real_query_filesystem_info_async (GFile *file,
+ const char *attributes,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *res;
+ QueryFilesystemInfoAsyncData *data;
+
+ data = g_new0 (QueryFilesystemInfoAsyncData, 1);
+ data->attributes = g_strdup (attributes);
+
+ res = g_simple_async_result_new (G_OBJECT (file), callback, user_data, g_file_real_query_filesystem_info_async);
+ g_simple_async_result_set_op_res_gpointer (res, data, (GDestroyNotify)query_filesystem_info_data_free);
+
+ g_simple_async_result_run_in_thread (res, query_filesystem_info_async_thread, io_priority, cancellable);
+ g_object_unref (res);
+}
+
+static GFileInfo *
+g_file_real_query_filesystem_info_finish (GFile *file,
+ GAsyncResult *res,
+ GError **error)
+{
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
+ QueryFilesystemInfoAsyncData *data;
+
+ g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_file_real_query_filesystem_info_async);
+
+ data = g_simple_async_result_get_op_res_gpointer (simple);
+ if (data->info)
+ return g_object_ref (data->info);
+
+ return NULL;
+}
+
+typedef struct {
+ char *attributes;
GFileQueryInfoFlags flags;
GFileEnumerator *enumerator;
} EnumerateChildrenAsyncData;
iface = G_FILE_GET_IFACE (object);
+ if (iface->read_fn == NULL)
+ {
+ g_set_error_literal (&error, G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ _("Operation not supported"));
+
+ g_simple_async_result_set_from_error (res, error);
+ g_error_free (error);
+
+ return;
+ }
+
stream = iface->read_fn (G_FILE (object), cancellable, &error);
if (stream == NULL)
}
static void
-g_file_real_replace_async (GFile *file,
- const char *etag,
- gboolean make_backup,
- GFileCreateFlags flags,
- int io_priority,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
+g_file_real_replace_async (GFile *file,
+ const char *etag,
+ gboolean make_backup,
+ GFileCreateFlags flags,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *res;
+ ReplaceAsyncData *data;
+
+ data = g_new0 (ReplaceAsyncData, 1);
+ data->etag = g_strdup (etag);
+ data->make_backup = make_backup;
+ data->flags = flags;
+
+ res = g_simple_async_result_new (G_OBJECT (file), callback, user_data, g_file_real_replace_async);
+ g_simple_async_result_set_op_res_gpointer (res, data, (GDestroyNotify)replace_async_data_free);
+
+ g_simple_async_result_run_in_thread (res, replace_async_thread, io_priority, cancellable);
+ g_object_unref (res);
+}
+
+static GFileOutputStream *
+g_file_real_replace_finish (GFile *file,
+ GAsyncResult *res,
+ GError **error)
+{
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
+ ReplaceAsyncData *data;
+
+ g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_file_real_replace_async);
+
+ data = g_simple_async_result_get_op_res_gpointer (simple);
+ if (data->stream)
+ return g_object_ref (data->stream);
+
+ return NULL;
+}
+
+static void
+open_readwrite_async_thread (GSimpleAsyncResult *res,
+ GObject *object,
+ GCancellable *cancellable)
+{
+ GFileIface *iface;
+ GFileIOStream *stream;
+ GError *error = NULL;
+
+ iface = G_FILE_GET_IFACE (object);
+
+ if (iface->open_readwrite == NULL)
+ {
+ g_set_error_literal (&error, G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ _("Operation not supported"));
+
+ g_simple_async_result_set_from_error (res, error);
+ g_error_free (error);
+
+ return;
+ }
+
+ stream = iface->open_readwrite (G_FILE (object), cancellable, &error);
+
+ if (stream == NULL)
+ {
+ g_simple_async_result_set_from_error (res, error);
+ g_error_free (error);
+ }
+ else
+ g_simple_async_result_set_op_res_gpointer (res, stream, g_object_unref);
+}
+
+static void
+g_file_real_open_readwrite_async (GFile *file,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *res;
+
+ res = g_simple_async_result_new (G_OBJECT (file), callback, user_data, g_file_real_open_readwrite_async);
+
+ g_simple_async_result_run_in_thread (res, open_readwrite_async_thread, io_priority, cancellable);
+ g_object_unref (res);
+}
+
+static GFileIOStream *
+g_file_real_open_readwrite_finish (GFile *file,
+ GAsyncResult *res,
+ GError **error)
+{
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
+ gpointer op;
+
+ g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_file_real_open_readwrite_async);
+
+ op = g_simple_async_result_get_op_res_gpointer (simple);
+ if (op)
+ return g_object_ref (op);
+
+ return NULL;
+}
+
+static void
+create_readwrite_async_thread (GSimpleAsyncResult *res,
+ GObject *object,
+ GCancellable *cancellable)
+{
+ GFileIface *iface;
+ GFileCreateFlags *data;
+ GFileIOStream *stream;
+ GError *error = NULL;
+
+ iface = G_FILE_GET_IFACE (object);
+
+ data = g_simple_async_result_get_op_res_gpointer (res);
+
+ if (iface->create_readwrite == NULL)
+ {
+ g_set_error_literal (&error, G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ _("Operation not supported"));
+
+ g_simple_async_result_set_from_error (res, error);
+ g_error_free (error);
+
+ return;
+ }
+
+ stream = iface->create_readwrite (G_FILE (object), *data, cancellable, &error);
+
+ if (stream == NULL)
+ {
+ g_simple_async_result_set_from_error (res, error);
+ g_error_free (error);
+ }
+ else
+ g_simple_async_result_set_op_res_gpointer (res, stream, g_object_unref);
+}
+
+static void
+g_file_real_create_readwrite_async (GFile *file,
+ GFileCreateFlags flags,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GFileCreateFlags *data;
+ GSimpleAsyncResult *res;
+
+ data = g_new0 (GFileCreateFlags, 1);
+ *data = flags;
+
+ res = g_simple_async_result_new (G_OBJECT (file), callback, user_data, g_file_real_create_readwrite_async);
+ g_simple_async_result_set_op_res_gpointer (res, data, (GDestroyNotify)g_free);
+
+ g_simple_async_result_run_in_thread (res, create_readwrite_async_thread, io_priority, cancellable);
+ g_object_unref (res);
+}
+
+static GFileIOStream *
+g_file_real_create_readwrite_finish (GFile *file,
+ GAsyncResult *res,
+ GError **error)
+{
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
+ gpointer op;
+
+ g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_file_real_create_readwrite_async);
+
+ op = g_simple_async_result_get_op_res_gpointer (simple);
+ if (op)
+ return g_object_ref (op);
+
+ return NULL;
+}
+
+typedef struct {
+ GFileIOStream *stream;
+ char *etag;
+ gboolean make_backup;
+ GFileCreateFlags flags;
+} ReplaceRWAsyncData;
+
+static void
+replace_rw_async_data_free (ReplaceRWAsyncData *data)
+{
+ if (data->stream)
+ g_object_unref (data->stream);
+ g_free (data->etag);
+ g_free (data);
+}
+
+static void
+replace_readwrite_async_thread (GSimpleAsyncResult *res,
+ GObject *object,
+ GCancellable *cancellable)
+{
+ GFileIface *iface;
+ GFileIOStream *stream;
+ GError *error = NULL;
+ ReplaceRWAsyncData *data;
+
+ iface = G_FILE_GET_IFACE (object);
+
+ data = g_simple_async_result_get_op_res_gpointer (res);
+
+ stream = iface->replace_readwrite (G_FILE (object),
+ data->etag,
+ data->make_backup,
+ data->flags,
+ cancellable,
+ &error);
+
+ if (stream == NULL)
+ {
+ g_simple_async_result_set_from_error (res, error);
+ g_error_free (error);
+ }
+ else
+ data->stream = stream;
+}
+
+static void
+g_file_real_replace_readwrite_async (GFile *file,
+ const char *etag,
+ gboolean make_backup,
+ GFileCreateFlags flags,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
GSimpleAsyncResult *res;
- ReplaceAsyncData *data;
+ ReplaceRWAsyncData *data;
- data = g_new0 (ReplaceAsyncData, 1);
+ data = g_new0 (ReplaceRWAsyncData, 1);
data->etag = g_strdup (etag);
data->make_backup = make_backup;
data->flags = flags;
- res = g_simple_async_result_new (G_OBJECT (file), callback, user_data, g_file_real_replace_async);
- g_simple_async_result_set_op_res_gpointer (res, data, (GDestroyNotify)replace_async_data_free);
+ res = g_simple_async_result_new (G_OBJECT (file), callback, user_data, g_file_real_replace_readwrite_async);
+ g_simple_async_result_set_op_res_gpointer (res, data, (GDestroyNotify)replace_rw_async_data_free);
- g_simple_async_result_run_in_thread (res, replace_async_thread, io_priority, cancellable);
+ g_simple_async_result_run_in_thread (res, replace_readwrite_async_thread, io_priority, cancellable);
g_object_unref (res);
}
-static GFileOutputStream *
-g_file_real_replace_finish (GFile *file,
- GAsyncResult *res,
- GError **error)
+static GFileIOStream *
+g_file_real_replace_readwrite_finish (GFile *file,
+ GAsyncResult *res,
+ GError **error)
{
GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
- ReplaceAsyncData *data;
+ ReplaceRWAsyncData *data;
- g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_file_real_replace_async);
+ g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_file_real_replace_readwrite_async);
data = g_simple_async_result_get_op_res_gpointer (simple);
if (data->stream)
return g_object_ref (data->stream);
-
+
return NULL;
}
return g_ascii_isalnum (c) || c == '+' || c == '-' || c == '.';
}
+/* Following RFC 2396, valid schemes are built like:
+ * scheme = alpha *( alpha | digit | "+" | "-" | "." )
+ */
static gboolean
has_valid_scheme (const char *uri)
{
p = uri;
- if (!is_valid_scheme_character (*p))
+ if (!g_ascii_isalpha (*p))
return FALSE;
do {
/**
* g_file_mount_enclosing_volume:
* @location: input #GFile.
+ * @flags: flags affecting the operation
* @mount_operation: a #GMountOperation or %NULL to avoid user interaction.
* @cancellable: optional #GCancellable object, %NULL to ignore.
* @callback: a #GAsyncReadyCallback to call when the request is satisfied, or %NULL.
**/
void
g_file_mount_enclosing_volume (GFile *location,
+ GMountMountFlags flags,
GMountOperation *mount_operation,
GCancellable *cancellable,
GAsyncReadyCallback callback,
return;
}
- (* iface->mount_enclosing_volume) (location, mount_operation, cancellable, callback, user_data);
+ (* iface->mount_enclosing_volume) (location, flags, mount_operation, cancellable, callback, user_data);
}
* Utility functions *
********************************************/
+/**
+ * g_file_query_default_handler:
+ * @file: a #GFile to open.
+ * @cancellable: optional #GCancellable object, %NULL to ignore.
+ * @error: a #GError, or %NULL
+ *
+ * Returns the #GAppInfo that is registered as the default
+ * application to handle the file specified by @file.
+ *
+ * If @cancellable is not %NULL, then the operation can be cancelled by
+ * triggering the cancellable object from another thread. If the operation
+ * was cancelled, the error %G_IO_ERROR_CANCELLED will be returned.
+ *
+ * Returns: a #GAppInfo if the handle was found, %NULL if there were errors.
+ * When you are done with it, release it with g_object_unref()
+ **/
+GAppInfo *
+g_file_query_default_handler (GFile *file,
+ GCancellable *cancellable,
+ GError **error)
+{
+ char *uri_scheme;
+ const char *content_type;
+ GAppInfo *appinfo;
+ GFileInfo *info;
+ char *path;
+
+ uri_scheme = g_file_get_uri_scheme (file);
+ if (uri_scheme && uri_scheme[0] != '\0')
+ {
+ appinfo = g_app_info_get_default_for_uri_scheme (uri_scheme);
+ g_free (uri_scheme);
+
+ if (appinfo != NULL)
+ return appinfo;
+ }
+
+ info = g_file_query_info (file,
+ G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
+ 0,
+ cancellable,
+ error);
+ if (info == NULL)
+ return NULL;
+
+ appinfo = NULL;
+
+ content_type = g_file_info_get_content_type (info);
+ if (content_type)
+ {
+ /* Don't use is_native(), as we want to support fuse paths if availible */
+ path = g_file_get_path (file);
+ appinfo = g_app_info_get_default_for_type (content_type,
+ path == NULL);
+ g_free (path);
+ }
+
+ g_object_unref (info);
+
+ if (appinfo != NULL)
+ return appinfo;
+
+ g_set_error_literal (error, G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ _("No application is registered as handling this file"));
+ return NULL;
+
+}
+
+
#define GET_CONTENT_BLOCK_SIZE 8192
/**
* @file: input #GFile.
* @cancellable: optional #GCancellable object, %NULL to ignore.
* @contents: a location to place the contents of the file.
- * @length: a location to place the length of the contents of the file.
- * @etag_out: a location to place the current entity tag for the file.
+ * @length: a location to place the length of the contents of the file,
+ * or %NULL if the length is not needed
+ * @etag_out: a location to place the current entity tag for the file,
+ * or %NULL if the entity tag is not needed
* @error: a #GError, or %NULL
*
- * Loads the content of the file into memory, returning the size of
- * the data. The data is always zero terminated, but this is not
- * included in the resultant @length.
+ * Loads the content of the file into memory. The data is always
+ * zero-terminated, but this is not included in the resultant @length.
+ * The returned @content should be freed with g_free() when no longer
+ * needed.
*
* If @cancellable is not %NULL, then the operation can be cancelled by
* triggering the cancellable object from another thread. If the operation
* was cancelled, the error %G_IO_ERROR_CANCELLED will be returned.
*
* Returns: %TRUE if the @file's contents were successfully loaded.
- * %FALSE if there were errors..
+ * %FALSE if there were errors.
**/
gboolean
g_file_load_contents (GFile *file,
* @file: input #GFile.
* @res: a #GAsyncResult.
* @contents: a location to place the contents of the file.
- * @length: a location to place the length of the contents of the file.
- * @etag_out: a location to place the current entity tag for the file.
+ * @length: a location to place the length of the contents of the file,
+ * or %NULL if the length is not needed
+ * @etag_out: a location to place the current entity tag for the file,
+ * or %NULL if the entity tag is not needed
* @error: a #GError, or %NULL
*
* Finishes an asynchronous partial load operation that was started
- * with g_file_load_partial_contents_async().
+ * with g_file_load_partial_contents_async(). The data is always
+ * zero-terminated, but this is not included in the resultant @length.
+ * The returned @content should be freed with g_free() when no longer
+ * needed.
*
* Returns: %TRUE if the load was successful. If %FALSE and @error is
* present, it will be set appropriately.
* @file: input #GFile.
* @res: a #GAsyncResult.
* @contents: a location to place the contents of the file.
- * @length: a location to place the length of the contents of the file.
- * @etag_out: a location to place the current entity tag for the file.
+ * @length: a location to place the length of the contents of the file,
+ * or %NULL if the length is not needed
+ * @etag_out: a location to place the current entity tag for the file,
+ * or %NULL if the entity tag is not needed
* @error: a #GError, or %NULL
*
* Finishes an asynchronous load of the @file's contents.
* The contents are placed in @contents, and @length is set to the
- * size of the @contents string. If @etag_out is present, it will be
+ * size of the @contents string. The @content should be freed with
+ * g_free() when no longer needed. If @etag_out is present, it will be
* set to the new entity tag for the @file.
*
* Returns: %TRUE if the load was successful. If %FALSE and @error is
* @contents: a string containing the new contents for @file.
* @length: the length of @contents in bytes.
* @etag: the old <link linkend="gfile-etag">entity tag</link>
- * for the document.
+ * for the document, or %NULL
* @make_backup: %TRUE if a backup should be created.
* @flags: a set of #GFileCreateFlags.
* @new_etag: a location to a new <link linkend="gfile-etag">entity tag</link>
* for the document. This should be freed with g_free() when no longer
- * needed.
+ * needed, or %NULL
* @cancellable: optional #GCancellable object, %NULL to ignore.
* @error: a #GError, or %NULL
*
GFileOutputStream *out;
gsize pos, remainder;
gssize res;
+ gboolean ret;
g_return_val_if_fail (G_IS_FILE (file), FALSE);
g_return_val_if_fail (contents != NULL, FALSE);
{
/* Ignore errors on close */
g_output_stream_close (G_OUTPUT_STREAM (out), cancellable, NULL);
-
+ g_object_unref (out);
+
/* error is set already */
return FALSE;
}
- if (!g_output_stream_close (G_OUTPUT_STREAM (out), cancellable, error))
- return FALSE;
+ ret = g_output_stream_close (G_OUTPUT_STREAM (out), cancellable, error);
if (new_etag)
*new_etag = g_file_output_stream_get_etag (out);
-
- return TRUE;
+
+ g_object_unref (out);
+
+ return ret;
}
typedef struct {
* @file: input #GFile.
* @contents: string of contents to replace the file with.
* @length: the length of @contents in bytes.
- * @etag: a new <link linkend="gfile-etag">entity tag</link> for the @file.
+ * @etag: a new <link linkend="gfile-etag">entity tag</link> for the @file, or %NULL
* @make_backup: %TRUE if a backup should be created.
* @flags: a set of #GFileCreateFlags.
* @cancellable: optional #GCancellable object, %NULL to ignore.
* @res: a #GAsyncResult.
* @new_etag: a location of a new <link linkend="gfile-etag">entity tag</link>
* for the document. This should be freed with g_free() when it is no
- * longer needed.
+ * longer needed, or %NULL
* @error: a #GError, or %NULL
*
* Finishes an asynchronous replace of the given @file. See
return TRUE;
}
+/**
+ * g_file_start_mountable:
+ * @file: input #GFile.
+ * @flags: flags affecting the operation
+ * @start_operation: a #GMountOperation, or %NULL to avoid user interaction.
+ * @cancellable: optional #GCancellable object, %NULL to ignore.
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied, or %NULL.
+ * @user_data: the data to pass to callback function
+ *
+ * Starts a file of type G_FILE_TYPE_MOUNTABLE.
+ * Using @start_operation, you can request callbacks when, for instance,
+ * passwords are needed during authentication.
+ *
+ * If @cancellable is not %NULL, then the operation can be cancelled by
+ * triggering the cancellable object from another thread. If the operation
+ * was cancelled, the error %G_IO_ERROR_CANCELLED will be returned.
+ *
+ * When the operation is finished, @callback will be called. You can then call
+ * g_file_mount_mountable_finish() to get the result of the operation.
+ *
+ * Since: 2.22
+ */
+void
+g_file_start_mountable (GFile *file,
+ GDriveStartFlags flags,
+ GMountOperation *start_operation,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GFileIface *iface;
+
+ g_return_if_fail (G_IS_FILE (file));
+
+ iface = G_FILE_GET_IFACE (file);
+
+ if (iface->start_mountable == NULL)
+ {
+ g_simple_async_report_error_in_idle (G_OBJECT (file),
+ callback,
+ user_data,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ _("Operation not supported"));
+ return;
+ }
+
+ (* iface->start_mountable) (file,
+ flags,
+ start_operation,
+ cancellable,
+ callback,
+ user_data);
+}
+
+/**
+ * g_file_start_mountable_finish:
+ * @file: input #GFile.
+ * @result: a #GAsyncResult.
+ * @error: a #GError, or %NULL
+ *
+ * Finishes a start operation. See g_file_start_mountable() for details.
+ *
+ * Finish an asynchronous start operation that was started
+ * with g_file_start_mountable().
+ *
+ * Returns: %TRUE if the operation finished successfully. %FALSE
+ * otherwise.
+ *
+ * Since: 2.22
+ */
+gboolean
+g_file_start_mountable_finish (GFile *file,
+ GAsyncResult *result,
+ GError **error)
+{
+ GFileIface *iface;
+
+ g_return_val_if_fail (G_IS_FILE (file), 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_FILE_GET_IFACE (file);
+ return (* iface->start_mountable_finish) (file, result, error);
+}
+
+/**
+ * g_file_stop_mountable:
+ * @file: input #GFile.
+ * @flags: flags affecting the operation
+ * @mount_operation: a #GMountOperation, or %NULL to avoid user interaction.
+ * @cancellable: optional #GCancellable object, %NULL to ignore.
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied, or %NULL.
+ * @user_data: the data to pass to callback function
+ *
+ * Stops a file of type G_FILE_TYPE_MOUNTABLE.
+ *
+ * If @cancellable is not %NULL, then the operation can be cancelled by
+ * triggering the cancellable object from another thread. If the operation
+ * was cancelled, the error %G_IO_ERROR_CANCELLED will be returned.
+ *
+ * When the operation is finished, @callback will be called. You can then call
+ * g_file_stop_mountable_finish() to get the result of the operation.
+ *
+ * Since: 2.22
+ */
+void
+g_file_stop_mountable (GFile *file,
+ GMountUnmountFlags flags,
+ GMountOperation *mount_operation,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GFileIface *iface;
+
+ g_return_if_fail (G_IS_FILE (file));
+
+ iface = G_FILE_GET_IFACE (file);
+
+ if (iface->stop_mountable == NULL)
+ {
+ g_simple_async_report_error_in_idle (G_OBJECT (file),
+ callback,
+ user_data,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ _("Operation not supported"));
+ return;
+ }
+
+ (* iface->stop_mountable) (file,
+ flags,
+ mount_operation,
+ cancellable,
+ callback,
+ user_data);
+}
+
+/**
+ * g_file_stop_mountable_finish:
+ * @file: input #GFile.
+ * @result: a #GAsyncResult.
+ * @error: a #GError, or %NULL
+ *
+ * Finishes an stop operation, see g_file_stop_mountable() for details.
+ *
+ * Finish an asynchronous stop operation that was started
+ * with g_file_stop_mountable().
+ *
+ * Returns: %TRUE if the operation finished successfully. %FALSE
+ * otherwise.
+ *
+ * Since: 2.22
+ */
+gboolean
+g_file_stop_mountable_finish (GFile *file,
+ GAsyncResult *result,
+ GError **error)
+{
+ GFileIface *iface;
+
+ g_return_val_if_fail (G_IS_FILE (file), 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_FILE_GET_IFACE (file);
+ return (* iface->stop_mountable_finish) (file, result, error);
+}
+
+/**
+ * g_file_poll_mountable:
+ * @file: input #GFile.
+ * @cancellable: optional #GCancellable object, %NULL to ignore.
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied, or %NULL.
+ * @user_data: the data to pass to callback function
+ *
+ * Polls a file of type G_FILE_TYPE_MOUNTABLE.
+ *
+ * If @cancellable is not %NULL, then the operation can be cancelled by
+ * triggering the cancellable object from another thread. If the operation
+ * was cancelled, the error %G_IO_ERROR_CANCELLED will be returned.
+ *
+ * When the operation is finished, @callback will be called. You can then call
+ * g_file_mount_mountable_finish() to get the result of the operation.
+ *
+ * Since: 2.22
+ */
+void
+g_file_poll_mountable (GFile *file,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GFileIface *iface;
+
+ g_return_if_fail (G_IS_FILE (file));
+
+ iface = G_FILE_GET_IFACE (file);
+
+ if (iface->poll_mountable == NULL)
+ {
+ g_simple_async_report_error_in_idle (G_OBJECT (file),
+ callback,
+ user_data,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ _("Operation not supported"));
+ return;
+ }
+
+ (* iface->poll_mountable) (file,
+ cancellable,
+ callback,
+ user_data);
+}
+
+/**
+ * g_file_poll_mountable_finish:
+ * @file: input #GFile.
+ * @result: a #GAsyncResult.
+ * @error: a #GError, or %NULL
+ *
+ * Finishes a poll operation. See g_file_poll_mountable() for details.
+ *
+ * Finish an asynchronous poll operation that was polled
+ * with g_file_poll_mountable().
+ *
+ * Returns: %TRUE if the operation finished successfully. %FALSE
+ * otherwise.
+ *
+ * Since: 2.22
+ */
+gboolean
+g_file_poll_mountable_finish (GFile *file,
+ GAsyncResult *result,
+ GError **error)
+{
+ GFileIface *iface;
+
+ g_return_val_if_fail (G_IS_FILE (file), 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_FILE_GET_IFACE (file);
+ return (* iface->poll_mountable_finish) (file, result, error);
+}
+
+/**
+ * g_file_supports_thread_contexts:
+ * @file: a #GFile.
+ *
+ * Checks if @file supports <link
+ * linkend="g-main-context-push-thread-default-context">thread-default
+ * contexts</link>. If this returns %FALSE, you cannot perform
+ * asynchronous operations on @file in a thread that has a
+ * thread-default context.
+ *
+ * Returns: Whether or not @file supports thread-default contexts.
+ *
+ * Since: 2.22
+ */
+gboolean
+g_file_supports_thread_contexts (GFile *file)
+{
+ GFileIface *iface;
+
+ g_return_val_if_fail (G_IS_FILE (file), FALSE);
+
+ iface = G_FILE_GET_IFACE (file);
+ return iface->supports_thread_contexts;
+}
+
#define __G_FILE_C__
#include "gioaliasdef.c"