summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilip Withnall <pwithnall@endlessos.org>2023-03-17 13:16:02 +0000
committerPhilip Withnall <pwithnall@endlessos.org>2023-05-09 13:53:44 +0100
commit0da948a5d13faa9d39c2170125edf51bdce301aa (patch)
tree3eaa48f935d22972affc7f2bfc9dd63680e7223b
parent63e1e83c339aab6f2c48f6bb6a68fc6197510ce9 (diff)
downloadglib-0da948a5d13faa9d39c2170125edf51bdce301aa.tar.gz
gfile: Eliminate a stat() call from the file copy code
The start of the `g_file_copy()` implementation stats the source file to find all the attributes to copy onto the destination file, so it makes sense to get it to store the source file size at the same time. This saves a subsequent `stat()` call on the source FD in the btrfs reflink or splice code. Every little helps. Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
-rw-r--r--gio/gfile.c23
1 files changed, 13 insertions, 10 deletions
diff --git a/gio/gfile.c b/gio/gfile.c
index 94786c84a..4558f2d3b 100644
--- a/gio/gfile.c
+++ b/gio/gfile.c
@@ -2807,6 +2807,11 @@ g_file_build_attribute_list_for_copy (GFile *file,
first = TRUE;
s = g_string_new ("");
+ /* Always query the source file size, even though we can’t set that on the
+ * destination. This is useful for the copy functions. */
+ first = FALSE;
+ g_string_append (s, G_FILE_ATTRIBUTE_STANDARD_SIZE);
+
if (attributes)
{
for (i = 0; i < attributes->n_infos; i++)
@@ -3042,6 +3047,7 @@ retry:
static gboolean
splice_stream_with_progress (GInputStream *in,
+ GFileInfo *in_info,
GOutputStream *out,
GCancellable *cancellable,
GFileProgressCallback progress_callback,
@@ -3085,10 +3091,8 @@ splice_stream_with_progress (GInputStream *in,
/* 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;
+ g_assert (g_file_info_has_attribute (in_info, G_FILE_ATTRIBUTE_STANDARD_SIZE));
+ total_size = g_file_info_get_size (in_info);
}
if (total_size == -1)
@@ -3151,6 +3155,7 @@ splice_stream_with_progress (GInputStream *in,
#ifdef __linux__
static gboolean
btrfs_reflink_with_progress (GInputStream *in,
+ GFileInfo *in_info,
GOutputStream *out,
GFileInfo *info,
GCancellable *cancellable,
@@ -3169,10 +3174,8 @@ btrfs_reflink_with_progress (GInputStream *in,
/* 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;
+ g_assert (g_file_info_has_attribute (in_info, G_FILE_ATTRIBUTE_STANDARD_SIZE));
+ total_size = g_file_info_get_size (in_info);
}
if (total_size == -1)
@@ -3376,7 +3379,7 @@ file_copy_fallback (GFile *source,
{
GError *reflink_err = NULL;
- if (!btrfs_reflink_with_progress (in, out, info, cancellable,
+ if (!btrfs_reflink_with_progress (in, info, out, info, cancellable,
progress_callback, progress_callback_data,
&reflink_err))
{
@@ -3403,7 +3406,7 @@ file_copy_fallback (GFile *source,
{
GError *splice_err = NULL;
- if (!splice_stream_with_progress (in, out, cancellable,
+ if (!splice_stream_with_progress (in, info, out, cancellable,
progress_callback, progress_callback_data,
&splice_err))
{