summaryrefslogtreecommitdiff
path: root/client/gvfsfusedaemon.c
diff options
context:
space:
mode:
authorTomas Bzatek <tbzatek@redhat.com>2012-06-25 17:32:01 +0200
committerTomas Bzatek <tbzatek@redhat.com>2012-06-25 17:37:03 +0200
commitff748cd275fba9b6cc14f1efa94534fbf0f23caa (patch)
tree80ecff83bbe8730fd5c665dd60111515ebf0ce7d /client/gvfsfusedaemon.c
parenta1abfe3ea48e92ae96a6d867272c9cf31bece9f7 (diff)
downloadgvfs-ff748cd275fba9b6cc14f1efa94534fbf0f23caa.tar.gz
fuse: Split padding size in blocks for ftruncate()
Don't allocate whole padding block, write in smaller pieces instead. As an bonus, check for block write result and break if error occurred, passing it further up. Found by David Zeuthen.
Diffstat (limited to 'client/gvfsfusedaemon.c')
-rw-r--r--client/gvfsfusedaemon.c27
1 files changed, 23 insertions, 4 deletions
diff --git a/client/gvfsfusedaemon.c b/client/gvfsfusedaemon.c
index 78279239..c760f14c 100644
--- a/client/gvfsfusedaemon.c
+++ b/client/gvfsfusedaemon.c
@@ -1845,6 +1845,28 @@ file_handle_get_size (FileHandle *fh,
return res;
}
+#define PAD_BLOCK_SIZE 65536
+
+static gint
+pad_file (FileHandle *fh, gsize num, goffset current_size)
+{
+ gpointer buf;
+ gsize written;
+ gint res;
+
+ res = 0;
+ buf = g_malloc0 (PAD_BLOCK_SIZE);
+ for (written = 0; written < num; written += PAD_BLOCK_SIZE)
+ {
+ res = write_stream (fh, buf, MIN (num - written, PAD_BLOCK_SIZE), current_size + written);
+ if (res < 0)
+ break;
+ }
+ g_free (buf);
+
+ return (res < 0 ? res : 0);
+}
+
static gint
vfs_ftruncate (const gchar *path, off_t size, struct fuse_file_info *fi)
{
@@ -1902,10 +1924,7 @@ vfs_ftruncate (const gchar *path, off_t size, struct fuse_file_info *fi)
/* If the truncated size is larger than the current size
* then we need to pad out the difference with 0's */
goffset orig_pos = g_seekable_tell (G_SEEKABLE (fh->stream));
- gsize buf_size = size - current_size;
- gpointer buf = g_malloc0 (buf_size);
- write_stream (fh, buf, buf_size, current_size);
- g_free (buf);
+ result = pad_file (fh, size - current_size, current_size);
g_seekable_seek (G_SEEKABLE (fh->stream), orig_pos, G_SEEK_SET, NULL, NULL);
}
}