+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+
/* GIO - GLib Input, Output and Streaming Library
*
* Copyright (C) 2006-2007 Red Hat, Inc.
/**
* 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 filesystem 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 (dupplicated 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, which is then passed to the function's matching _finish()
+ * the operation, producing a GAsyncResult which is then passed to the
+ * function's matching _finish()
* operation.
*
* Some #GFile operations do not have synchronous analogs, as they may
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,
- int io_priority,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data);
-static GFileInfo * g_file_real_query_info_finish (GFile *file,
- GAsyncResult *res,
- GError **error);
-static void g_file_real_enumerate_children_async (GFile *file,
- const char *attributes,
- GFileQueryInfoFlags flags,
- int io_priority,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data);
-static GFileEnumerator * g_file_real_enumerate_children_finish (GFile *file,
- GAsyncResult *res,
- GError **error);
-static void g_file_real_read_async (GFile *file,
- int io_priority,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data);
-static GFileInputStream * g_file_real_read_finish (GFile *file,
- GAsyncResult *res,
- GError **error);
-static void g_file_real_append_to_async (GFile *file,
- GFileCreateFlags flags,
- int io_priority,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data);
-static GFileOutputStream *g_file_real_append_to_finish (GFile *file,
- GAsyncResult *res,
- GError **error);
-static void g_file_real_create_async (GFile *file,
- GFileCreateFlags flags,
- int io_priority,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data);
-static GFileOutputStream *g_file_real_create_finish (GFile *file,
- GAsyncResult *res,
- GError **error);
-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);
-static GFileOutputStream *g_file_real_replace_finish (GFile *file,
- GAsyncResult *res,
- GError **error);
-static gboolean g_file_real_set_attributes_from_info (GFile *file,
- GFileInfo *info,
- GFileQueryInfoFlags flags,
- GCancellable *cancellable,
- GError **error);
-static void g_file_real_set_display_name_async (GFile *file,
- const char *display_name,
- int io_priority,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data);
-static GFile * g_file_real_set_display_name_finish (GFile *file,
- GAsyncResult *res,
- GError **error);
-static void g_file_real_set_attributes_async (GFile *file,
- GFileInfo *info,
- GFileQueryInfoFlags flags,
- int io_priority,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data);
-static gboolean g_file_real_set_attributes_finish (GFile *file,
- GAsyncResult *res,
- GFileInfo **info,
- GError **error);
+static void g_file_real_query_info_async (GFile *file,
+ const char *attributes,
+ GFileQueryInfoFlags flags,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+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,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+static GFileEnumerator * g_file_real_enumerate_children_finish (GFile *file,
+ GAsyncResult *res,
+ GError **error);
+static void g_file_real_read_async (GFile *file,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+static GFileInputStream * g_file_real_read_finish (GFile *file,
+ GAsyncResult *res,
+ GError **error);
+static void g_file_real_append_to_async (GFile *file,
+ GFileCreateFlags flags,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+static GFileOutputStream *g_file_real_append_to_finish (GFile *file,
+ GAsyncResult *res,
+ GError **error);
+static void g_file_real_create_async (GFile *file,
+ GFileCreateFlags flags,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+static GFileOutputStream *g_file_real_create_finish (GFile *file,
+ GAsyncResult *res,
+ GError **error);
+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);
+static GFileOutputStream *g_file_real_replace_finish (GFile *file,
+ GAsyncResult *res,
+ GError **error);
+static gboolean g_file_real_set_attributes_from_info (GFile *file,
+ GFileInfo *info,
+ GFileQueryInfoFlags flags,
+ GCancellable *cancellable,
+ GError **error);
+static void g_file_real_set_display_name_async (GFile *file,
+ const char *display_name,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+static GFile * g_file_real_set_display_name_finish (GFile *file,
+ GAsyncResult *res,
+ GError **error);
+static void g_file_real_set_attributes_async (GFile *file,
+ GFileInfo *info,
+ GFileQueryInfoFlags flags,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+static gboolean g_file_real_set_attributes_finish (GFile *file,
+ GAsyncResult *res,
+ GFileInfo **info,
+ GError **error);
+static void g_file_real_find_enclosing_mount_async (GFile *file,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+static GMount * g_file_real_find_enclosing_mount_finish (GFile *file,
+ GAsyncResult *res,
+ GError **error);
+static void g_file_real_copy_async (GFile *source,
+ GFile *destination,
+ GFileCopyFlags flags,
+ int io_priority,
+ GCancellable *cancellable,
+ GFileProgressCallback progress_callback,
+ gpointer progress_callback_data,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+static gboolean g_file_real_copy_finish (GFile *file,
+ GAsyncResult *res,
+ GError **error);
GType
g_file_get_type (void)
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->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_async = g_file_real_copy_async;
+ iface->copy_finish = g_file_real_copy_finish;
}
static void
* e.g. "C:\Windows" or "/usr/bin/". This does not mean the file is local,
* as it might be on a locally mounted remote filesystem.
*
- * On some systems non-native files may be availible using
+ * On some systems non-native files may be available using
* the native filesystem via a userspace filesystem (FUSE), in
* these cases this call will return %FALSE, but g_file_get_path()
* will still return a native path.
* g_file_get_basename:
* @file: input #GFile.
*
- * Gets the basename (the last component of the path) for a given #GFile.
+ * Gets the base name (the last component of the path) for a given #GFile.
*
- * If called for the toplevel of a system (such as the filesystem root
- * or a uri like sftp://host/ it will return a single directory separator
+ * 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
* (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
* @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.
*
/**
* 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
}
/**
- * g_file_contains_file:
- * @parent: input #GFile.
- * @descendant: input #GFile.
- *
- * Checks whether @parent (recursively) contains the specified @descendent.
+ * 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.
*
- * Returns: %TRUE if the @descendent'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
+ * 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 *
* all the files in the directory.
*
* The @attribute value is a string that specifies the file attributes that
- * should be gathered. It is not an error if its not possible to read a particular
- * requested attribute from a file, it just won't be set. @attribute should
+ * should be gathered. It is not an error if it's not possible to read a particular
+ * requested attribute from a file - it just won't be set. @attribute should
* be a comma-separated list of attribute or attribute wildcards. The wildcard "*"
- * means all attributes, and a wildcard like "std:*" means all attributes in the std
- * namespace. An example attribute query be "std:*,owner:user".
- * The standard attributes are availible as defines, like #G_FILE_ATTRIBUTE_STD_NAME.
+ * means all attributes, and a wildcard like "standard::*" means all attributes in the standard
+ * namespace. An example attribute query be "standard::*,owner::user".
+ * The standard attributes are available as defines, like #G_FILE_ATTRIBUTE_STANDARD_NAME.
*
* If @cancellable is not %NULL, then the operation can be cancelled by
* triggering the cancellable object from another thread. If the operation
return (* iface->enumerate_children_finish) (file, res, error);
}
+/**
+ * g_file_query_exists:
+ * @file: input #GFile.
+ * @cancellable: optional #GCancellable object, %NULL to ignore.
+ *
+ * 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 existence
+ * and then execute something based on the outcome of that, because 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.
+ *
+ * As an example of race-free checking, take the case of reading a file, and
+ * if it doesn't exist, creating it. There are two racy versions: read it, and
+ * on error create it; and: check if it exists, if not create it. These
+ * can both result in two processes creating the file (with perhaps a partially
+ * written file as the result). The correct approach is to always try to create
+ * 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 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
+ * errors that can happen due to races when you execute the operation.
+ *
+ * Returns: %TRUE if the file exists (and can be detected without error), %FALSE otherwise (or if cancelled).
+ */
+gboolean
+g_file_query_exists (GFile *file,
+ 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);
+ if (info != NULL)
+ {
+ g_object_unref (info);
+ return TRUE;
+ }
+
+ return FALSE;
+}
/**
* g_file_query_info:
* @error: a #GError.
*
* Gets the requested information about specified @file. The result
- * is a #GFileInfo objects that contains key-value attributes (like type or size
- * for the file.
+ * is a #GFileInfo object that contains key-value attributes (such as
+ * the type or size of the file).
*
* The @attribute value is a string that specifies the file attributes that
- * should be gathered. It is not an error if its not possible to read a particular
- * requested attribute from a file, it just won't be set. @attribute should
+ * should be gathered. It is not an error if it's not possible to read a particular
+ * requested attribute from a file - it just won't be set. @attribute should
* be a comma-separated list of attribute or attribute wildcards. The wildcard "*"
- * means all attributes, and a wildcard like "std:*" means all attributes in the std
- * namespace. An example attribute query be "std:*,owner:user".
- * The standard attributes are availible as defines, like #G_FILE_ATTRIBUTE_STD_NAME.
+ * means all attributes, and a wildcard like "standard::*" means all attributes in the standard
+ * namespace. An example attribute query be "standard::*,owner::user".
+ * The standard attributes are available as defines, like #G_FILE_ATTRIBUTE_STANDARD_NAME.
*
* If @cancellable is not %NULL, then the operation can be cancelled by
* triggering the cancellable object from another thread. If the operation
* symlink is returned, rather than information about the symlink itself.
* However if you pass #G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS in @flags the
* information about the symlink itself will be returned. Also, for symlinks
- * that points to non-existing files the information about the symlink itself
+ * that point to non-existing files the information about the symlink itself
* will be returned.
*
* If the file does not exist, the G_IO_ERROR_NOT_FOUND error will be returned.
* @user_data: the data to pass to callback function
*
* Asynchronously gets the requested information about specified @file. The result
- * is a #GFileInfo objects that contains key-value attributes (like type or size
- * for the file.
+ * is a #GFileInfo object that contains key-value attributes (such as type or size
+ * for the file).
*
* For more details, see g_file_query_info() which is
* the synchronous version of this call.
*
* When the operation is finished, @callback will be called. You can then call
- * g_file_enumerate_children_finish() to get the result of the operation.
+ * g_file_query_info_finish() to get the result of the operation.
**/
void
g_file_query_info_async (GFile *file,
*
* Similar to g_file_query_info(), but obtains information
* about the filesystem the @file is on, rather than the file itself.
- * For instance the amount of space availible and the type of
+ * For instance the amount of space available and the type of
* the filesystem.
*
* The @attribute value is a string that specifies the file attributes that
- * should be gathered. It is not an error if its not possible to read a particular
- * requested attribute from a file, it just won't be set. @attribute should
+ * should be gathered. It is not an error if it's not possible to read a particular
+ * requested attribute from a file - it just won't be set. @attribute should
* be a comma-separated list of attribute or attribute wildcards. The wildcard "*"
* means all attributes, and a wildcard like "fs:*" means all attributes in the fs
* namespace. The standard namespace for filesystem attributes is "fs".
- * Common attributes of interest are #G_FILE_ATTRIBUTE_FS_SIZE
- * (the total size of the filesystem in bytes), #G_FILE_ATTRIBUTE_FS_FREE (number of
- * bytes availible), and #G_FILE_ATTRIBUTE_FS_TYPE (type of the filesystem).
+ * Common attributes of interest are #G_FILE_ATTRIBUTE_FILESYSTEM_SIZE
+ * (the total size of the filesystem in bytes), #G_FILE_ATTRIBUTE_FILESYSTEM_FREE (number of
+ * bytes available), and #G_FILE_ATTRIBUTE_FILESYSTEM_TYPE (type of the filesystem).
*
* If @cancellable is not %NULL, then the operation can be cancelled by
* triggering the cancellable object from another thread. If the operation
}
/**
+ * 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.
+ **/
+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.
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 (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
+ * @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 mount for the file.
+ *
+ * For more details, see g_file_find_enclosing_mount() which is
+ * the synchronous version of this call.
+ *
+ * When the operation is finished, @callback will be called. You can then call
+ * g_file_find_enclosing_mount_finish() to get the result of the operation.
+ */
+void
+g_file_find_enclosing_mount_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->find_enclosing_mount_async) (file,
+ io_priority,
+ cancellable,
+ callback,
+ user_data);
+}
+
+/**
+ * g_file_find_enclosing_mount_finish:
+ * @file: a #GFile
+ * @res: a #GAsyncResult
+ * @error: a #GError
+ *
+ * Finishes an asynchronous find mount request.
+ * See g_file_find_enclosing_mount_async().
+ *
+ * Returns: #GMount for given @file or %NULL on error.
+ **/
+GMount *
+g_file_find_enclosing_mount_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->find_enclosing_mount_finish) (file, res, error);
+}
+
/**
* g_file_read:
* triggering the cancellable object from another thread. If the operation
* was cancelled, the error %G_IO_ERROR_CANCELLED will be returned.
*
- * Some filesystems don't allow all filenames, and may
+ * 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
* returned. Other errors are possible too, and depend on what kind of
* 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 filesystems don't allow all filenames, and may
+ * Some file systems don't allow all file names, and may
* return an G_IO_ERROR_INVALID_FILENAME error, and if the name
* is to long G_IO_ERROR_FILENAME_TOO_LONG will be returned.
* Other errors are possible too, and depend on what kind of
* If the file is a directory the G_IO_ERROR_IS_DIRECTORY error will be returned,
* and if the file is some other form of non-regular file then a
* G_IO_ERROR_NOT_REGULAR_FILE error will be returned.
- * Some filesystems don't allow all filenames, and may
+ * Some file systems don't allow all file names, and may
* return an G_IO_ERROR_INVALID_FILENAME error, and if the name
* is to long G_IO_ERROR_FILENAME_TOO_LONG will be returned.
* Other errors are possible too, and depend on what kind of
* Asynchronously creates a new file and returns an output stream for writing to it.
* The file must not already exists.
*
- * For more details, see g_file_creat() which is
+ * For more details, see g_file_create() which is
* the synchronous version of this call.
*
* When the operation is finished, @callback will be called. You can then call
* g_file_replace_async:
* @file: input #GFile.
* @etag: an <link linkend="gfile-etag">entity tag</link> for the
- * current #GFile.
- * @make_backup: a #gboolean.
+ * 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.
* @callback: a #GAsyncReadyCallback to call when the request is satisfied
* @user_data: the data to pass to callback function
*
- * Asyncronously overwrites the file, replacing the contents, possibly
+ * Asynchronously overwrites the file, replacing the contents, possibly
* creating a backup copy of the file first.
*
* For more details, see g_file_replace() which is
/* Don't overwrite if the destination is a directory */
- info = g_file_query_info (destination, G_FILE_ATTRIBUTE_STD_TYPE,
+ info = g_file_query_info (destination, G_FILE_ATTRIBUTE_STANDARD_TYPE,
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
cancellable, &my_error);
if (info != NULL)
g_error_free (my_error);
my_error = NULL;
- info = g_file_query_info (destination, G_FILE_ATTRIBUTE_STD_TYPE,
+ info = g_file_query_info (destination, G_FILE_ATTRIBUTE_STANDARD_TYPE,
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
cancellable, &my_error);
if (info != NULL)
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;
+ total_size = -1;
info = g_file_input_stream_query_info (G_FILE_INPUT_STREAM (in),
- G_FILE_ATTRIBUTE_STD_SIZE,
+ G_FILE_ATTRIBUTE_STANDARD_SIZE,
cancellable, NULL);
if (info)
{
- total_size = g_file_info_get_size (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);
}
/* 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);
if (flags & G_FILE_COPY_NOFOLLOW_SYMLINKS)
{
info = g_file_query_info (source,
- G_FILE_ATTRIBUTE_STD_TYPE "," G_FILE_ATTRIBUTE_STD_SYMLINK_TARGET,
+ G_FILE_ATTRIBUTE_STANDARD_TYPE "," G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET,
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
cancellable,
error);
return FALSE;
}
- if (!copy_stream_with_progress (in, out, cancellable,
+ if (!copy_stream_with_progress (in, out, source, cancellable,
progress_callback, progress_callback_data,
error))
return FALSE;
* @flags: set of #GFileCopyFlags
* @cancellable: optional #GCancellable object, %NULL to ignore.
* @progress_callback: function to callback with progress information
- * @progress_callback_data: userdata to pass to @progress_callback
+ * @progress_callback_data: user data to pass to @progress_callback
* @error: #GError to set on error, or %NULL
*
* Copies the file @source to the location specified by @destination.
* If @progress_callback is not %NULL, then the operation can be monitored by
* setting this to a #GFileProgressCallback function. @progress_callback_data
* will be passed to this function. It is guaranteed that this callback will
- * be called after all data has been transfered with the total number of bytes
+ * be called after all data has been transferred with the total number of bytes
* copied during the operation.
*
* If the @source file does not exist then the G_IO_ERROR_NOT_FOUND
if (g_cancellable_set_error_if_cancelled (cancellable, error))
return FALSE;
- if (G_OBJECT_TYPE (source) == G_OBJECT_TYPE (destination))
+ iface = G_FILE_GET_IFACE (destination);
+ if (iface->copy)
{
- iface = G_FILE_GET_IFACE (source);
+ my_error = NULL;
+ res = (* iface->copy) (source, destination,
+ flags, cancellable,
+ progress_callback, progress_callback_data,
+ &my_error);
+
+ if (res)
+ return TRUE;
+
+ if (my_error->domain != G_IO_ERROR || my_error->code != G_IO_ERROR_NOT_SUPPORTED)
+ {
+ g_propagate_error (error, my_error);
+ return FALSE;
+ }
+ }
+ /* If the types are different, and the destination method failed
+ also try the source method */
+ if (G_OBJECT_TYPE (source) != G_OBJECT_TYPE (destination))
+ {
+ iface = G_FILE_GET_IFACE (source);
+
if (iface->copy)
{
my_error = NULL;
- res = (* iface->copy) (source, destination, flags, cancellable, progress_callback, progress_callback_data, &my_error);
+ res = (* iface->copy) (source, destination,
+ flags, cancellable,
+ progress_callback, progress_callback_data,
+ &my_error);
if (res)
return TRUE;
}
}
}
-
+
return file_copy_fallback (source, destination, flags, cancellable,
progress_callback, progress_callback_data,
error);
}
+/**
+ * g_file_copy_async:
+ * @source: input #GFile.
+ * @destination: destination #GFile
+ * @flags: set of #GFileCopyFlags
+ * @io_priority: the <link linkend="io-priority">I/O priority</link>
+ * of the request.
+ * @cancellable: optional #GCancellable object, %NULL to ignore.
+ * @progress_callback: function to callback with progress information
+ * @progress_callback_data: user data to pass to @progress_callback
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: the data to pass to callback function
+ *
+ * Copies the file @source to the location specified by @destination
+ * asynchronously. For details of the behaviour, see g_file_copy().
+ *
+ * If @progress_callback is not %NULL, then that function that will be called
+ * just like in g_file_copy(), however the callback will run in the main loop,
+ * not in the thread that is doing the I/O operation.
+ *
+ * When the operation is finished, @callback will be called. You can then call
+ * g_file_copy_finish() to get the result of the operation.
+ **/
+void
+g_file_copy_async (GFile *source,
+ GFile *destination,
+ GFileCopyFlags flags,
+ int io_priority,
+ GCancellable *cancellable,
+ GFileProgressCallback progress_callback,
+ gpointer progress_callback_data,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GFileIface *iface;
+
+ g_return_if_fail (G_IS_FILE (source));
+ g_return_if_fail (G_IS_FILE (destination));
+
+ iface = G_FILE_GET_IFACE (source);
+ (* iface->copy_async) (source,
+ destination,
+ flags,
+ io_priority,
+ cancellable,
+ progress_callback,
+ progress_callback_data,
+ callback,
+ user_data);
+}
+
+/**
+ * g_file_copy_finish:
+ * @file: input #GFile.
+ * @res: a #GAsyncResult.
+ * @error: a #GError, or %NULL
+ *
+ * Finishes copying the file started with
+ * g_file_copy_async().
+ *
+ * Returns: a %TRUE on success, %FALSE on error.
+ **/
+gboolean
+g_file_copy_finish (GFile *file,
+ GAsyncResult *res,
+ GError **error)
+{
+ GFileIface *iface;
+
+ g_return_val_if_fail (G_IS_FILE (file), FALSE);
+ g_return_val_if_fail (G_IS_ASYNC_RESULT (res), FALSE);
+
+ if (G_IS_SIMPLE_ASYNC_RESULT (res))
+ {
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return FALSE;
+ }
+
+ iface = G_FILE_GET_IFACE (file);
+ return (* iface->copy_finish) (file, res, error);
+}
/**
* g_file_move:
*
*
* Tries to move the file or directory @source to the location specified by @destination.
- * If native move operations is supported then this is used, otherwise a copy + delete
+ * If native move operations are supported then this is used, otherwise a copy + delete
* fallback is used. The native implementation may support moving directories (for instance
* on moves inside the same filesystem), but the fallback code does not.
*
* If @progress_callback is not %NULL, then the operation can be monitored by
* setting this to a #GFileProgressCallback function. @progress_callback_data
* will be passed to this function. It is guaranteed that this callback will
- * be called after all data has been transfered with the total number of bytes
+ * be called after all data has been transferred with the total number of bytes
* copied during the operation.
*
* If the @source file does not exist then the G_IO_ERROR_NOT_FOUND
*
* If the source is a directory and the target does not exist, or #G_FILE_COPY_OVERWRITE is
* specified and the target is a file, then the G_IO_ERROR_WOULD_RECURSE error
- * may be returned (if the native move operation isn't availible).
+ * may be returned (if the native move operation isn't available).
*
* Returns: %TRUE on successful move, %FALSE otherwise.
**/
if (g_cancellable_set_error_if_cancelled (cancellable, error))
return FALSE;
- if (G_OBJECT_TYPE (source) == G_OBJECT_TYPE (destination))
+ iface = G_FILE_GET_IFACE (destination);
+ if (iface->move)
{
- iface = G_FILE_GET_IFACE (source);
+ my_error = NULL;
+ res = (* iface->move) (source, destination,
+ flags, cancellable,
+ progress_callback, progress_callback_data,
+ &my_error);
+
+ if (res)
+ return TRUE;
+
+ if (my_error->domain != G_IO_ERROR || my_error->code != G_IO_ERROR_NOT_SUPPORTED)
+ {
+ g_propagate_error (error, my_error);
+ return FALSE;
+ }
+ }
+ /* If the types are different, and the destination method failed
+ also try the source method */
+ if (G_OBJECT_TYPE (source) != G_OBJECT_TYPE (destination))
+ {
+ iface = G_FILE_GET_IFACE (source);
+
if (iface->move)
{
my_error = NULL;
- res = (* iface->move) (source, destination, flags, cancellable, progress_callback, progress_callback_data, &my_error);
+ res = (* iface->move) (source, destination,
+ flags, cancellable,
+ progress_callback, progress_callback_data,
+ &my_error);
if (res)
return TRUE;
}
}
}
-
+
if (flags & G_FILE_COPY_NO_FALLBACK_FOR_MOVE)
{
g_set_error (error, G_IO_ERROR,
* @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
*
* Sends @file to the "Trashcan", if possible. This is similar to
* deleting it, but the user can recover it before emptying the trashcan.
- * Not all filesystems support trashing, so this call can return the
+ * Not all file systems support trashing, so this call can return the
* %G_IO_ERROR_NOT_SUPPORTED error.
*
*
* filesystem if possible and the @file is renamed to this.
*
* If you want to implement a rename operation in the user interface the edit name
- * (#G_FILE_ATTRIBUTE_STD_EDIT_NAME) should be used as the initial value in the rename
+ * (#G_FILE_ATTRIBUTE_STANDARD_EDIT_NAME) should be used as the initial value in the rename
* widget, and then the result after editing should be passed to g_file_set_display_name().
*
* On success the resulting converted filename is returned.
* @user_data: the data to pass to callback function
*
* Asynchronously sets the display name for a given #GFile.
- * For the synchronous version of this function, see g_file_set_display_name().
+ *
+ * For more details, see g_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_finish() to get the result of the operation.
**/
void
g_file_set_display_name_async (GFile *file,
* @user_data: a #gpointer.
*
* Asynchronously sets the attributes of @file with @info.
- * For the synchronous version of this function, see g_file_set_attributes().
+ *
+ * For more details, see g_file_set_attributes_from_info() which is
+ * the synchronous version of this call.
+ *
+ * When the operation is finished, @callback will be called. You can then call
+ * g_file_set_attributes_finish() to get the result of the operation.
**/
void
g_file_set_attributes_async (GFile *file,
/**
* 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
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied, or %NULL.
* @user_data: the data to pass to callback function
*
* Mounts a file of type G_FILE_TYPE_MOUNTABLE.
- * You can speciy using @mount_operation to get callbacks when for instance
+ * Using @mount_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
**/
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,
/**
* g_file_unmount_mountable:
* @file: input #GFile.
+ * @flags: flags affecting the operation
* @cancellable: optional #GCancellable object, %NULL to ignore.
- * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @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.
* 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.
+ * g_file_unmount_mountable_finish() to get the result of the operation.
**/
void
g_file_unmount_mountable (GFile *file,
+ GMountUnmountFlags flags,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
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,
cancellable,
callback,
user_data);
/**
* g_file_eject_mountable:
* @file: input #GFile.
+ * @flags: flags affecting the operation
* @cancellable: optional #GCancellable object, %NULL to ignore.
- * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @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.
**/
void
g_file_eject_mountable (GFile *file,
+ GMountUnmountFlags flags,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
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,
cancellable,
callback,
user_data);
* @file: input #GFile.
* @flags: a set of #GFileMonitorFlags.
* @cancellable: optional #GCancellable object, %NULL to ignore.
+ * @error: a #GError, or %NULL.
*
* Obtains a directory monitor for the given file.
* This may fail if directory monitoring is not supported.
* triggering the cancellable object from another thread. If the operation
* was cancelled, the error %G_IO_ERROR_CANCELLED will be returned.
*
- * Returns: a #GDirectoryMonitor for the given @file,
+ * Returns: a #GFileMonitor for the given @file,
* or %NULL on error.
**/
-GDirectoryMonitor*
+GFileMonitor*
g_file_monitor_directory (GFile *file,
GFileMonitorFlags flags,
- GCancellable *cancellable)
+ 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->monitor_dir == NULL)
- return NULL;
+ {
+ g_set_error (error, G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ _("Operation not supported"));
+ return NULL;
+ }
- return (* iface->monitor_dir) (file, flags, cancellable);
+ return (* iface->monitor_dir) (file, flags, cancellable, error);
}
/**
* @file: input #GFile.
* @flags: a set of #GFileMonitorFlags.
* @cancellable: optional #GCancellable object, %NULL to ignore.
+ * @error: a #GError, or %NULL.
*
* Obtains a file monitor for the given file. If no file notification
* mechanism exists, then regular polling of the file is used.
GFileMonitor*
g_file_monitor_file (GFile *file,
GFileMonitorFlags flags,
- GCancellable *cancellable)
+ GCancellable *cancellable,
+ GError **error)
{
GFileIface *iface;
GFileMonitor *monitor;
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);
monitor = NULL;
if (iface->monitor_file)
- monitor = (* iface->monitor_file) (file, flags, cancellable);
+ monitor = (* iface->monitor_file) (file, flags, cancellable, NULL);
/* Fallback to polling */
if (monitor == NULL)
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;
return data->res;
}
+static void
+find_enclosing_mount_async_thread (GSimpleAsyncResult *res,
+ GObject *object,
+ GCancellable *cancellable)
+{
+ GError *error = NULL;
+ GMount *mount;
+
+ mount = g_file_find_enclosing_mount (G_FILE (object), cancellable, &error);
+
+ if (mount == NULL)
+ {
+ g_simple_async_result_set_from_error (res, error);
+ g_error_free (error);
+ }
+ else
+ g_simple_async_result_set_op_res_gpointer (res, mount, (GDestroyNotify)g_object_unref);
+}
+
+static void
+g_file_real_find_enclosing_mount_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_find_enclosing_mount_async);
+
+ g_simple_async_result_run_in_thread (res, find_enclosing_mount_async_thread, io_priority, cancellable);
+ g_object_unref (res);
+}
+
+static GMount *
+g_file_real_find_enclosing_mount_finish (GFile *file,
+ GAsyncResult *res,
+ GError **error)
+{
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
+ GMount *mount;
+
+ g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_file_real_find_enclosing_mount_async);
+
+ mount = g_simple_async_result_get_op_res_gpointer (simple);
+ return g_object_ref (mount);
+}
+
+
+typedef struct {
+ GFile *source;
+ GFile *destination;
+ GFileCopyFlags flags;
+ GFileProgressCallback progress_cb;
+ gpointer progress_cb_data;
+ GIOSchedulerJob *job;
+} CopyAsyncData;
+
+static void
+copy_async_data_free (CopyAsyncData *data)
+{
+ g_object_unref (data->source);
+ g_object_unref (data->destination);
+ g_free (data);
+}
+
+typedef struct {
+ CopyAsyncData *data;
+ goffset current_num_bytes;
+ goffset total_num_bytes;
+} ProgressData;
+
+static gboolean
+copy_async_progress_in_main (gpointer user_data)
+{
+ ProgressData *progress = user_data;
+ CopyAsyncData *data = progress->data;
+
+ data->progress_cb (progress->current_num_bytes,
+ progress->total_num_bytes,
+ data->progress_cb_data);
+
+ return FALSE;
+}
+
+static gboolean
+mainloop_barrier (gpointer user_data)
+{
+ /* Does nothing, but ensures all queued idles before
+ this are run */
+ return FALSE;
+}
+
+
+static void
+copy_async_progress_callback (goffset current_num_bytes,
+ goffset total_num_bytes,
+ gpointer user_data)
+{
+ CopyAsyncData *data = user_data;
+ ProgressData *progress;
+
+ progress = g_new (ProgressData, 1);
+ progress->data = data;
+ progress->current_num_bytes = current_num_bytes;
+ progress->total_num_bytes = total_num_bytes;
+
+ g_io_scheduler_job_send_to_mainloop_async (data->job,
+ copy_async_progress_in_main,
+ progress,
+ g_free);
+}
+
+static gboolean
+copy_async_thread (GIOSchedulerJob *job,
+ GCancellable *cancellable,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *res;
+ CopyAsyncData *data;
+ gboolean result;
+ GError *error;
+
+ res = user_data;
+ data = g_simple_async_result_get_op_res_gpointer (res);
+
+ error = NULL;
+ data->job = job;
+ result = g_file_copy (data->source,
+ data->destination,
+ data->flags,
+ cancellable,
+ (data->progress_cb != NULL) ? copy_async_progress_callback : NULL,
+ data,
+ &error);
+
+ /* Ensure all progress callbacks are done running in main thread */
+ if (data->progress_cb != NULL)
+ g_io_scheduler_job_send_to_mainloop (job,
+ mainloop_barrier,
+ NULL, NULL);
+
+ if (!result)
+ {
+ g_simple_async_result_set_from_error (res, error);
+ g_error_free (error);
+ }
+
+ g_simple_async_result_complete_in_idle (res);
+
+ return FALSE;
+}
+
+static void
+g_file_real_copy_async (GFile *source,
+ GFile *destination,
+ GFileCopyFlags flags,
+ int io_priority,
+ GCancellable *cancellable,
+ GFileProgressCallback progress_callback,
+ gpointer progress_callback_data,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *res;
+ CopyAsyncData *data;
+
+ data = g_new0 (CopyAsyncData, 1);
+ data->source = g_object_ref (source);
+ data->destination = g_object_ref (destination);
+ data->flags = flags;
+ data->progress_cb = progress_callback;
+ data->progress_cb_data = progress_callback_data;
+
+ res = g_simple_async_result_new (G_OBJECT (source), callback, user_data, g_file_real_copy_async);
+ g_simple_async_result_set_op_res_gpointer (res, data, (GDestroyNotify)copy_async_data_free);
+
+ g_io_scheduler_push_job (copy_async_thread, res, g_object_unref, io_priority, cancellable);
+}
+
+static gboolean
+g_file_real_copy_finish (GFile *file,
+ GAsyncResult *res,
+ GError **error)
+{
+ /* Error handled in g_file_copy_finish() */
+ return TRUE;
+}
+
+
/********************************************
* Default VFS operations *
********************************************/
* g_file_new_for_commandline_arg:
* @arg: a command line string.
*
- * Creates a #GFile with the given argument from
- * the command line.
- *
+ * Creates a #GFile with the given argument from the command line. The value of
+ * @arg can be either a URI, an absolute path or a relative path resolved
+ * relative to the current working directory.
+ * This operation never fails, but the returned object might not support any
+ * I/O operation if @arg points to a malformed path.
+ *
* Returns: a new #GFile.
**/
GFile *
/**
* 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
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied, or %NULL.
* @user_data: the data to pass to callback function
*
* Starts a @mount_operation, mounting the volume that contains the file @location.
**/
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);
}
* Finishes a mount operation started by g_file_mount_enclosing_volume().
*
* Returns: %TRUE if successful. If an error
- * has occured, this function will return %FALSE and set @error
+ * has occurred, this function will return %FALSE and set @error
* appropriately if present.
**/
gboolean
* 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);
+ 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 (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
/**
* g_file_load_partial_contents_async:
* @file: input #GFile.
* @cancellable: optional #GCancellable object, %NULL to ignore.
- * @read_more_callback: a #GFileReadMoreCallback.
+ * @read_more_callback: a #GFileReadMoreCallback to receive partial data and to specify whether further data should be read.
* @callback: a #GAsyncReadyCallback to call when the request is satisfied
* @user_data: the data to pass to the callback functions.
*
* @callback: a #GAsyncReadyCallback to call when the request is satisfied
* @user_data: the data to pass to callback function
*
- * Starts an asynchronous load of the @file's contents.
+ * Starts an asynchronous load of the @file's contents.
+ *
+ * For more details, see g_file_load_contents() which is
+ * the synchronous version of this call.
+ *
* When the load operation has completed, @callback will be called
- * with @userdata. To finish the operation, call
+ * with @user data. To finish the operation, call
* g_file_load_contents_finish() with the #GAsyncResult returned by
* the @callback.
*
* @length: the length of @contents in bytes.
* @etag: the old <link linkend="gfile-etag">entity tag</link>
* for the document.
- * @make_backup: a #gboolean.
+ * @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.
+ * for the document. This should be freed with g_free() when no longer
+ * needed.
* @cancellable: optional #GCancellable object, %NULL to ignore.
* @error: a #GError, or %NULL
*
* next time it is saved over.
*
* Returns: %TRUE if successful. If an error
- * has occured, this function will return %FALSE and set @error
+ * has occurred, this function will return %FALSE and set @error
* appropriately if present.
**/
gboolean
* @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.
- * @make_backup: a #gboolean.
+ * @make_backup: %TRUE if a backup should be created.
* @flags: a set of #GFileCreateFlags.
* @cancellable: optional #GCancellable object, %NULL to ignore.
* @callback: a #GAsyncReadyCallback to call when the request is satisfied
* @file: input #GFile.
* @res: a #GAsyncResult.
* @new_etag: a location of a new <link linkend="gfile-etag">entity tag</link>
- * for the document.
+ * for the document. This should be freed with g_free() when it is no
+ * longer needed.
* @error: a #GError, or %NULL
*
* Finishes an asynchronous replace of the given @file. See