summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorColin Walters <walters@verbum.org>2013-01-23 15:18:07 -0500
committerColin Walters <walters@verbum.org>2013-01-23 15:19:57 -0500
commit43a525fd40faf7dfd261bf3d7469f642a68fad68 (patch)
tree94689f1496f21a516986ce00ec004ef79e66f458
parent0c232faa9d74a39358d75a098af25776a2e00529 (diff)
downloadlibgsystem-43a525fd40faf7dfd261bf3d7469f642a68fad68.tar.gz
Decouple gsystem-local-alloc from libgsystem.h
I'd like some of the code here to possibly make its way into GLib. In order to accomplish that, we can't use the local allocation macros =/
-rw-r--r--gsystem-file-utils.c121
-rw-r--r--gsystem-shutil.c163
-rw-r--r--libgsystem.h1
3 files changed, 179 insertions, 106 deletions
diff --git a/gsystem-file-utils.c b/gsystem-file-utils.c
index f33bf41..140d53a 100644
--- a/gsystem-file-utils.c
+++ b/gsystem-file-utils.c
@@ -100,13 +100,13 @@ gs_file_read_noatime (GFile *file,
GCancellable *cancellable,
GError **error)
{
- gs_free char *path = NULL;
+ const char *path = NULL;
int fd;
if (g_cancellable_set_error_if_cancelled (cancellable, error))
return NULL;
- path = g_file_get_path (file);
+ path = gs_file_get_path_cached (file);
if (path == NULL)
return NULL;
@@ -290,6 +290,71 @@ gen_tmp_name (const char *prefix,
}
static gboolean
+linkcopy_internal_attempt (GFile *src,
+ GFile *dest,
+ GFile *dest_parent,
+ GFileCopyFlags flags,
+ gboolean sync_data,
+ gboolean enable_guestfs_fuse_workaround,
+ gboolean *out_try_again,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ gboolean ret_try_again = FALSE;
+ int res;
+ char *tmp_name = NULL;
+ GFile *tmp_dest = NULL;
+
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ goto out;
+
+ tmp_name = gen_tmp_name (NULL, NULL);
+ tmp_dest = g_file_get_child (dest_parent, tmp_name);
+
+ res = link (gs_file_get_path_cached (src), gs_file_get_path_cached (tmp_dest));
+ if (res == -1)
+ {
+ if (errno == EEXIST)
+ {
+ /* Nothing, fall through */
+ ret_try_again = TRUE;
+ ret = TRUE;
+ goto out;
+ }
+ else if (errno == EXDEV || errno == EMLINK || errno == EPERM
+ || (enable_guestfs_fuse_workaround && errno == ENOENT))
+ {
+ if (!g_file_copy (src, tmp_dest, flags,
+ cancellable, NULL, NULL, error))
+ goto out;
+ }
+ else
+ {
+ _set_error_from_errno (error);
+ goto out;
+ }
+ }
+
+ if (sync_data)
+ {
+ /* Now, we need to fdatasync */
+ if (!gs_file_sync_data (tmp_dest, cancellable, error))
+ goto out;
+ }
+
+ if (!gs_file_rename (tmp_dest, dest, cancellable, error))
+ goto out;
+
+ ret = TRUE;
+ *out_try_again = FALSE;
+ out:
+ g_clear_pointer (&tmp_name, g_free);
+ g_clear_object (&tmp_dest);
+ return ret;
+}
+
+static gboolean
linkcopy_internal (GFile *src,
GFile *dest,
GFileCopyFlags flags,
@@ -303,7 +368,7 @@ linkcopy_internal (GFile *src,
gboolean enable_guestfs_fuse_workaround;
struct stat src_stat;
struct stat dest_stat;
- gs_unref_object GFile *dest_parent = NULL;
+ GFile *dest_parent = NULL;
flags |= G_FILE_COPY_NOFOLLOW_SYMLINKS;
@@ -347,50 +412,22 @@ linkcopy_internal (GFile *src,
/* 128 attempts seems reasonable... */
for (i = 0; i < 128; i++)
{
- int res;
- gs_free char *tmp_name = NULL;
- gs_unref_object GFile *tmp_dest = NULL;
+ gboolean tryagain;
- if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ if (!linkcopy_internal_attempt (src, dest, dest_parent,
+ flags, sync_data,
+ enable_guestfs_fuse_workaround,
+ &tryagain,
+ cancellable, error))
goto out;
- tmp_name = gen_tmp_name (NULL, NULL);
- tmp_dest = g_file_get_child (dest_parent, tmp_name);
-
- res = link (gs_file_get_path_cached (src), gs_file_get_path_cached (tmp_dest));
- if (res == -1)
- {
- if (errno == EEXIST)
- continue;
- else if (errno == EXDEV || errno == EMLINK || errno == EPERM
- || (enable_guestfs_fuse_workaround && errno == ENOENT))
- {
- if (!g_file_copy (src, tmp_dest, flags,
- cancellable, NULL, NULL, error))
- goto out;
- }
- else
- {
- _set_error_from_errno (error);
- goto out;
- }
- }
-
- if (sync_data)
- {
- /* Now, we need to fdatasync */
- if (!gs_file_sync_data (tmp_dest, cancellable, error))
- goto out;
- }
-
- if (!gs_file_rename (tmp_dest, dest, cancellable, error))
- goto out;
-
- break;
+ if (!tryagain)
+ break;
}
ret = TRUE;
out:
+ g_clear_object (&dest_parent);
return ret;
}
@@ -654,14 +691,13 @@ gs_file_ensure_directory (GFile *dir,
{
gboolean ret = FALSE;
GError *temp_error = NULL;
+ GFile *parent = NULL;
if (!g_file_make_directory (dir, cancellable, &temp_error))
{
if (with_parents &&
g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
{
- gs_unref_object GFile *parent = NULL;
-
g_clear_error (&temp_error);
parent = g_file_get_parent (dir);
@@ -684,6 +720,7 @@ gs_file_ensure_directory (GFile *dir,
ret = TRUE;
out:
+ g_clear_object (&parent);
return ret;
}
diff --git a/gsystem-shutil.c b/gsystem-shutil.c
index 380acc4..dc62741 100644
--- a/gsystem-shutil.c
+++ b/gsystem-shutil.c
@@ -34,11 +34,91 @@ cp_internal (GFile *src,
GFile *dest,
gboolean use_hardlinks,
GCancellable *cancellable,
+ GError **error);
+
+static gboolean
+cp_internal_one_item (GFile *src,
+ GFile *dest,
+ GFileInfo *file_info,
+ gboolean use_hardlinks,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ const char *name = g_file_info_get_name (file_info);
+ GFile *src_child = g_file_get_child (src, name);
+ GFile *dest_child = g_file_get_child (dest, name);
+
+ if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_DIRECTORY)
+ {
+ if (!gs_file_ensure_directory (dest_child, FALSE, cancellable, error))
+ goto out;
+
+ /* Can't do this even though we'd like to; it fails with an error about
+ * setting standard::type not being supported =/
+ *
+ if (!g_file_set_attributes_from_info (dest_child, file_info, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+ cancellable, error))
+ goto out;
+ */
+ if (chmod (gs_file_get_path_cached (dest_child),
+ g_file_info_get_attribute_uint32 (file_info, "unix::mode")) == -1)
+ {
+ int errsv = errno;
+ g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (errsv),
+ g_strerror (errsv));
+ goto out;
+ }
+
+ if (!cp_internal (src_child, dest_child, use_hardlinks, cancellable, error))
+ goto out;
+ }
+ else
+ {
+ gboolean did_link = FALSE;
+ (void) unlink (gs_file_get_path_cached (dest_child));
+ if (use_hardlinks)
+ {
+ if (link (gs_file_get_path_cached (src_child), gs_file_get_path_cached (dest_child)) == -1)
+ {
+ if (!(errno == EMLINK || errno == EXDEV))
+ {
+ int errsv = errno;
+ g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (errsv),
+ g_strerror (errsv));
+ goto out;
+ }
+ use_hardlinks = FALSE;
+ }
+ else
+ did_link = TRUE;
+ }
+ if (!did_link)
+ {
+ if (!g_file_copy (src_child, dest_child,
+ G_FILE_COPY_OVERWRITE | G_FILE_COPY_ALL_METADATA | G_FILE_COPY_NOFOLLOW_SYMLINKS,
+ cancellable, NULL, NULL, error))
+ goto out;
+ }
+ }
+
+ ret = TRUE;
+ out:
+ g_clear_object (&src_child);
+ g_clear_object (&dest_child);
+ return ret;
+}
+
+static gboolean
+cp_internal (GFile *src,
+ GFile *dest,
+ gboolean use_hardlinks,
+ GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
- gs_unref_object GFileEnumerator *enumerator = NULL;
- gs_unref_object GFileInfo *file_info = NULL;
+ GFileEnumerator *enumerator = NULL;
+ GFileInfo *file_info = NULL;
GError *temp_error = NULL;
enumerator = g_file_enumerate_children (src, "standard::type,standard::name,unix::mode",
@@ -52,62 +132,9 @@ cp_internal (GFile *src,
while ((file_info = g_file_enumerator_next_file (enumerator, cancellable, &temp_error)) != NULL)
{
- const char *name = g_file_info_get_name (file_info);
- gs_unref_object GFile *src_child = g_file_get_child (src, name);
- gs_unref_object GFile *dest_child = g_file_get_child (dest, name);
-
- if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_DIRECTORY)
- {
- if (!gs_file_ensure_directory (dest_child, FALSE, cancellable, error))
- goto out;
-
- /* Can't do this even though we'd like to; it fails with an error about
- * setting standard::type not being supported =/
- *
- if (!g_file_set_attributes_from_info (dest_child, file_info, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
- cancellable, error))
- goto out;
- */
- if (chmod (gs_file_get_path_cached (dest_child),
- g_file_info_get_attribute_uint32 (file_info, "unix::mode")) == -1)
- {
- int errsv = errno;
- g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (errsv),
- g_strerror (errsv));
- goto out;
- }
-
- if (!cp_internal (src_child, dest_child, use_hardlinks, cancellable, error))
- goto out;
- }
- else
- {
- gboolean did_link = FALSE;
- (void) unlink (gs_file_get_path_cached (dest_child));
- if (use_hardlinks)
- {
- if (link (gs_file_get_path_cached (src_child), gs_file_get_path_cached (dest_child)) == -1)
- {
- if (!(errno == EMLINK || errno == EXDEV))
- {
- int errsv = errno;
- g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (errsv),
- g_strerror (errsv));
- goto out;
- }
- use_hardlinks = FALSE;
- }
- else
- did_link = TRUE;
- }
- if (!did_link)
- {
- if (!g_file_copy (src_child, dest_child,
- G_FILE_COPY_OVERWRITE | G_FILE_COPY_ALL_METADATA | G_FILE_COPY_NOFOLLOW_SYMLINKS,
- cancellable, NULL, NULL, error))
- goto out;
- }
- }
+ if (!cp_internal_one_item (src, dest, file_info, use_hardlinks,
+ cancellable, error))
+ goto out;
g_clear_object (&file_info);
}
if (temp_error)
@@ -118,6 +145,8 @@ cp_internal (GFile *src,
ret = TRUE;
out:
+ g_clear_object (&enumerator);
+ g_clear_object (&file_info);
return ret;
}
@@ -180,8 +209,8 @@ gs_shutil_rm_rf (GFile *path,
GError **error)
{
gboolean ret = FALSE;
- gs_unref_object GFileEnumerator *dir_enum = NULL;
- gs_unref_object GFileInfo *file_info = NULL;
+ GFileEnumerator *dir_enum = NULL;
+ GFileInfo *file_info = NULL;
GError *temp_error = NULL;
dir_enum = g_file_enumerate_children (path, "standard::type,standard::name",
@@ -209,7 +238,7 @@ gs_shutil_rm_rf (GFile *path,
while ((file_info = g_file_enumerator_next_file (dir_enum, cancellable, &temp_error)) != NULL)
{
- gs_unref_object GFile *subpath = NULL;
+ GFile *subpath = NULL;
GFileType type;
const char *name;
@@ -221,12 +250,18 @@ gs_shutil_rm_rf (GFile *path,
if (type == G_FILE_TYPE_DIRECTORY)
{
if (!gs_shutil_rm_rf (subpath, cancellable, error))
- goto out;
+ {
+ g_object_unref (subpath);
+ goto out;
+ }
}
else
{
if (!gs_file_unlink (subpath, cancellable, error))
- goto out;
+ {
+ g_object_unref (subpath);
+ goto out;
+ }
}
g_clear_object (&file_info);
}
@@ -241,6 +276,8 @@ gs_shutil_rm_rf (GFile *path,
ret = TRUE;
out:
+ g_clear_object (&dir_enum);
+ g_clear_object (&file_info);
return ret;
}
diff --git a/libgsystem.h b/libgsystem.h
index 1102b63..8c45633 100644
--- a/libgsystem.h
+++ b/libgsystem.h
@@ -25,7 +25,6 @@
G_BEGIN_DECLS
-#include <gsystem-local-alloc.h>
#include <gsystem-file-utils.h>
#include <gsystem-shutil.h>
#include <gsystem-subprocess.h>