diff options
author | Colin Walters <walters@verbum.org> | 2013-01-23 15:18:07 -0500 |
---|---|---|
committer | Colin Walters <walters@verbum.org> | 2013-01-23 15:19:57 -0500 |
commit | 43a525fd40faf7dfd261bf3d7469f642a68fad68 (patch) | |
tree | 94689f1496f21a516986ce00ec004ef79e66f458 | |
parent | 0c232faa9d74a39358d75a098af25776a2e00529 (diff) | |
download | libgsystem-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.c | 121 | ||||
-rw-r--r-- | gsystem-shutil.c | 163 | ||||
-rw-r--r-- | libgsystem.h | 1 |
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> |